From eaedd07f6c64fa9148ba1d7ebc8133575bafc2cb Mon Sep 17 00:00:00 2001 From: tt-cll <141346969+tt-cll@users.noreply.github.com> Date: Wed, 29 Jan 2025 18:49:39 -0500 Subject: [PATCH 01/43] add solana contracts to gitignore (#16128) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bf8606a8e30..a15b54a8f9d 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ benchmark_report.csv benchmark_summary.json secrets.toml tmp_laneconfig/ +solana_contracts # goreleaser builds cosign.* From 85dc3e56ebd3228649dbef69d4b4c87a0f2f9920 Mon Sep 17 00:00:00 2001 From: krehermann <16602512+krehermann@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:47:34 -0700 Subject: [PATCH 02/43] delete unused code (#16130) * delete unused code * fix scripts --- core/scripts/go.mod | 2 +- .../src/generate_local_ocr3_config.go | 9 +- deployment/keystone/deprecated.go | 127 ------------------ 3 files changed, 5 insertions(+), 133 deletions(-) delete mode 100644 deployment/keystone/deprecated.go diff --git a/core/scripts/go.mod b/core/scripts/go.mod index aa72e0f8298..0125129fa0e 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -13,7 +13,7 @@ replace github.com/smartcontractkit/chainlink/deployment => ../../deployment // creating potential merge conflicts. require ( github.com/smartcontractkit/chainlink/deployment v0.0.0-20250128231431-9279badae2f0 - github.com/smartcontractkit/chainlink/v2 v2.0.0-20250128231431-9279badae2f0 + github.com/smartcontractkit/chainlink/v2 v2.19.0-ccip1.5.16-alpha.0.0.20250129223716-34cbaaab2d04 ) require ( diff --git a/core/scripts/keystone/src/generate_local_ocr3_config.go b/core/scripts/keystone/src/generate_local_ocr3_config.go index c171c7f097d..68b1cade0c5 100644 --- a/core/scripts/keystone/src/generate_local_ocr3_config.go +++ b/core/scripts/keystone/src/generate_local_ocr3_config.go @@ -5,8 +5,7 @@ import ( "os" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/keystone" - ksdeploy "github.com/smartcontractkit/chainlink/deployment/keystone" + "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" ) type generateLocalOCR3Config struct{} @@ -67,7 +66,7 @@ func (g *generateLocalOCR3Config) Run(args []string) { "CSAPublicKey": "csa_1b874ac2d54b966cec5a8358678ca6f030261aabf3372ce9dbea2d4eb9cdab3d" }]`) - var pubKeys []ksdeploy.NodeKeys + var pubKeys []changeset.NodeKeys err := json.Unmarshal(publicKeys, &pubKeys) if err != nil { panic(err) @@ -94,13 +93,13 @@ func (g *generateLocalOCR3Config) Run(args []string) { "MaxDurationAcceptMillis": 1000, "MaxDurationTransmitMillis": 1000, "MaxFaultyOracles": 1}`) - var cfg keystone.OracleConfig + var cfg changeset.OracleConfig err = json.Unmarshal(config, &cfg) if err != nil { panic(err) } - ocrConfig, err := ksdeploy.GenerateOCR3Config(cfg, pubKeys, deployment.XXXGenerateTestOCRSecrets()) + ocrConfig, err := changeset.GenerateOCR3Config(cfg, pubKeys, deployment.XXXGenerateTestOCRSecrets()) if err != nil { panic(err) } diff --git a/deployment/keystone/deprecated.go b/deployment/keystone/deprecated.go deleted file mode 100644 index 71a462384e4..00000000000 --- a/deployment/keystone/deprecated.go +++ /dev/null @@ -1,127 +0,0 @@ -package keystone - -import "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" - -//TODO: delete this after the downstream migration is done - -// Deprecated: Use changeset package instead -// OracleConfig is the configuration for an oracle -type OracleConfig = changeset.OracleConfig - -// Deprecated: Use changeset package instead -// OCR3OnchainConfig is the onchain configuration of an OCR2 contract -type OCR2OracleConfig = changeset.OCR3OnchainConfig - -// Deprecated: Use changeset package instead -// NodeKeys is a set of public keys for a node -type NodeKeys = changeset.NodeKeys - -// Deprecated: Use changeset package instead -// TopLevelConfigSource is the top level configuration source -type TopLevelConfigSource = changeset.TopLevelConfigSource - -// Deprecated: Use changeset package instead -// GenerateOCR3Config generates an OCR3 config -var GenerateOCR3Config = changeset.GenerateOCR3Config - -// Deprecated: Use changeset package instead -// FeedConsumer is a feed consumer contract type -var FeedConsumer = changeset.FeedConsumer - -// Deprecated: Use changeset package instead -// KeystoneForwarder is a keystone forwarder contract type -var KeystoneForwarder = changeset.KeystoneForwarder - -// Deprecated: Use changeset package instead -// GetContractSetsRequest is a request to get contract sets -type GetContractSetsRequest = changeset.GetContractSetsRequest - -// Deprecated: Use changeset package instead -// GetContractSetsResponse is a response to get contract sets -type GetContractSetsResponse = changeset.GetContractSetsResponse - -// Deprecated: Use changeset package instead -// GetContractSets gets contract sets -var GetContractSets = changeset.GetContractSets - -// Deprecated: Use changeset package instead -// RegisterCapabilitiesRequest is a request to register capabilities -type RegisterCapabilitiesRequest = changeset.RegisterCapabilitiesRequest - -// Deprecated: Use changeset package instead -// RegisterCapabilitiesResponse is a response to register capabilities -type RegisterCapabilitiesResponse = changeset.RegisterCapabilitiesResponse - -// Deprecated: Use changeset package instead -// RegisterCapabilities registers capabilities -var RegisterCapabilities = changeset.RegisterCapabilities - -// Deprecated: Use changeset package instead -// RegisterNOPSRequest is a request to register NOPS -type RegisterNOPSRequest = changeset.RegisterNOPSRequest - -// Deprecated: Use changeset package instead -// RegisterNOPSResponse is a response to register NOPS -type RegisterNOPSResponse = changeset.RegisterNOPSResponse - -// Deprecated: Use changeset package instead -// RegisterNOPS registers NOPS -var RegisterNOPS = changeset.RegisterNOPS - -// Deprecated: Use changeset package instead -// RegisterNodesRequest is a request to register nodes with the capabilities registry -type RegisterNodesRequest = changeset.RegisterNodesRequest - -// Deprecated: Use changeset package instead -// RegisterNodesResponse is a response to register nodes with the capabilities registry -type RegisterNodesResponse = changeset.RegisterNodesResponse - -// Deprecated: Use changeset package instead -// RegisterNodes registers nodes with the capabilities registry -var RegisterNodes = changeset.RegisterNodes - -// Deprecated: Use changeset package instead -// RegisteredCapability is a wrapper of a capability and its ID -type RegisteredCapability = changeset.RegisteredCapability - -// Deprecated: Use changeset package instead -// FromCapabilitiesRegistryCapability converts a capabilities registry capability to a registered capability -var FromCapabilitiesRegistryCapability = changeset.FromCapabilitiesRegistryCapability - -// Deprecated: Use changeset package instead -// RegisterDonsRequest is a request to register Dons with the capabilities registry -type RegisterDonsRequest = changeset.RegisterDonsRequest - -// Deprecated: Use changeset package instead -// RegisterDonsResponse is a response to register Dons with the capabilities registry -type RegisterDonsResponse = changeset.RegisterDonsResponse - -// Deprecated: Use changeset package instead -// RegisterDons registers Dons with the capabilities registry -var RegisterDons = changeset.RegisterDons - -// Deprecated: Use changeset package instead -// DONToRegister is the minimal information needed to register a DON with the capabilities registry -type DONToRegister = changeset.DONToRegister - -// Deprecated: Use changeset package instead -// ConfigureContractsRequest is a request to configure ALL the contracts -type ConfigureContractsRequest = changeset.ConfigureContractsRequest - -// Deprecated: Use changeset package instead -// ConfigureContractsResponse is a response to configure ALL the contracts -type ConfigureContractsResponse = changeset.ConfigureContractsResponse - -// Deprecated: Use changeset package instead -// DonCapabilities is a set of capabilities hosted by a set of node operators -// in is in a convenient form to handle the CLO representation of the nop data -type DonCapabilities = changeset.DonCapabilities - -// Deprecated: Use changeset package instead -type DeployRequest = changeset.DeployRequest - -// Deprecated: Use changeset package instead -type DeployResponse = changeset.DeployResponse - -// Deprecated: Use changeset package instead -type ContractSet = changeset.ContractSet From d4292f3f676664f5b5ab144690f0c6c7168ec726 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 29 Jan 2025 18:48:31 -0600 Subject: [PATCH 03/43] core/services/chainlink: wrap cosmos relayer with ServerAdapter (#16131) --- core/services/chainlink/relayer_factory.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index f3c4544159e..392274703c0 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -328,7 +328,7 @@ func (r *RelayerFactory) NewCosmos(config CosmosFactoryConfig) (map[types.RelayI return nil, fmt.Errorf("failed to load Cosmos chain %q: %w", relayID, err) } - relayers[relayID] = cosmos.NewRelayer(lggr, chain) + relayers[relayID] = relay.NewServerAdapter(cosmos.NewRelayer(lggr, chain)) } } return relayers, nil From a46e7dd885d64ddf9a241dd86ba01e5e361ad995 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Thu, 30 Jan 2025 08:48:31 +0100 Subject: [PATCH 04/43] [TT-1969] add extra debug information to keystone smoke test (#16091) * add extra debug information * fix lint * poll config every 500ms * change polling interval to 1s * CR changes * move comments around * add test modification guideline and better debugging --- .github/e2e-tests.yml | 1 + .../smoke/capabilities/.gitignore | 4 +- .../smoke/capabilities/guidelines.md | 214 +++++++++++ .../smoke/capabilities/workflow_test.go | 332 +++++++++++++++++- 4 files changed, 531 insertions(+), 20 deletions(-) create mode 100644 integration-tests/smoke/capabilities/guidelines.md diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index 3c727c95aed..7c75d44fa92 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -194,6 +194,7 @@ runner-test-matrix: pyroscope_env: ci-smoke-capabilities-evm-simulated test_env_vars: E2E_TEST_CHAINLINK_VERSION: '{{ env.DEFAULT_CHAINLINK_PLUGINS_VERSION }}' # This is the chainlink version that has the plugins + GITHUB_READ_TOKEN: '{{ env.GITHUB_API_TOKEN }}' # GATI-provided token that can read from capabilities and dev-platform repos IS_CI: "true" CTF_CONFIGS: "environment-ci.toml" # Anvil developer key, not a secret diff --git a/integration-tests/smoke/capabilities/.gitignore b/integration-tests/smoke/capabilities/.gitignore index 6e48389b4c3..03d90d23455 100644 --- a/integration-tests/smoke/capabilities/.gitignore +++ b/integration-tests/smoke/capabilities/.gitignore @@ -1,4 +1,6 @@ # CTFv2 cached environment, no point in committing this *-cache.toml # compiled cron capability -amd64_cron \ No newline at end of file +amd64_cron +# workflow registration artifact +abcdefgasd.yaml \ No newline at end of file diff --git a/integration-tests/smoke/capabilities/guidelines.md b/integration-tests/smoke/capabilities/guidelines.md new file mode 100644 index 00000000000..4195bea12cb --- /dev/null +++ b/integration-tests/smoke/capabilities/guidelines.md @@ -0,0 +1,214 @@ +# Test Modification and Execution Guide + +## Table of Contents +1. [How to Run the Test](#how-to-run-the-test) +2. [Adding a New Capability](#adding-a-new-capability) + - [Copying the Binary to the Container](#copying-the-binary-to-the-container) + - [Registering the Capability in the Registry Contract](#registering-the-capability-in-the-registry-contract) + - [Creating a New Capability Job](#creating-a-new-capability-job) +3. [Using a New Workflow](#using-a-new-workflow) + - [Test Uploads the Binary](#test-uploads-the-binary) + - [Workflow Configuration](#workflow-configuration) + - [Workflow Secrets](#workflow-secrets) + - [Manual Upload of the Binary](#manual-upload-of-the-binary) +4. [Deployer Address or Deployment Sequence Changes](#deployer-address-or-deployment-sequence-changes) +5. [Multiple DONs](#multiple-dons) +6. [Using a Specific Docker Image for Chainlink Node](#using-a-specific-docker-image-for-chainlink-node) + +--- + +## How to Run the Test + +The test requires several environment variables. Below is a launch configuration that can be used with the VCS: + +```json +{ + "name": "Launch Capability Test", + "type": "go", + "request": "launch", + "mode": "test", + "program": "${workspaceFolder}/integration-tests/smoke/capabilities", + "env": { + "CTF_CONFIGS": "environment.toml", + "PRIVATE_KEY": "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "GITHUB_GIST_API_TOKEN": "your-gist-read:write-fpat-token", + "GITHUB_CAP_API_TOKEN": "your-capabilities-repo-content-read-fpat-token" + }, + "args": [ + "-test.run", + "TestKeystoneWithOCR3Workflow" + ] +} +``` + +- **`GITHUB_READ_TOKEN`**: Required for downloading the `cron` capability binary and `chainlink-cli` (if enabled). Requires `content:read` permission for `smartcontractkit/capabilities` and `smartcontractkit/dev-platform` repositories. Use a fine-grained personal access token (PAT) tied to the **organization’s GitHub account**. +- **`GIST_WRITE_TOKEN`**: Required only for compiling and uploading a new workflow. It needs `gist:read:write` permissions and should be a fine-grained PAT **tied to your personal GitHub account**. + +--- + +## Adding a New Capability + +To use a new capability in the test, follow these three steps: + +1. Copy the capability binary to the Chainlink node’s Docker container (must be in `linux/amd64` format). +2. Register the capability in the capability registry contract. +3. Create a new job on each worker node to launch the capability. + +Only after completing these steps can you run a workflow that requires the new capability. + +### Copying the Binary to the Container + +The test configuration is defined in a TOML file (`environment.toml`), which specifies properties for the Chainlink nodes. The `capabilities` property determines which binaries are copied to the container: + +```toml + [[nodeset.node_specs]] + + [nodeset.node_specs.node] + capabilities = ["./amd64_cron"] +``` + +This instructs the framework to copy `./amd64_cron` to the container’s `/home/capabilities/` directory, making it available as `/home/capabilities/amd64_cron`. + +> **Note:** While copying the binary to the bootstrap node causes no harm, it is unnecessary since the bootstrap node does not handle capability-related tasks. + +### Registering the Capability in the Registry Contract + +Next, register the new capability in the **capabilities registry contract** to make it accessible to the workflow DON. + +Example definition for a cron capability: + +```go +{ + LabelledName: "cron-trigger", + Version: "1.0.0", + CapabilityType: uint8(0), // trigger +} +``` + +Some capabilities may also require `ResponseType` or `ConfigurationContract`. Check with the capability author for the necessary values and ensure the correct capability type is set. + +Since this test's code is a living creature we do not indicate any line numbers or functions names. It's advised that you search for the example used above or usages of `CapabilitiesRegistryCapability` type. + +### Creating a New Capability Job + +Now that worker nodes have access to the binary and it is registered in the contract, create a capability job for each worker node. + +Example cron capability job: + +```toml +type = "standardcapabilities" +schemaVersion = 1 +name = "cron-capabilities" +forwardingAllowed = false +command = "/home/capabilities/amd64_cron" +config = "" +``` + +Since this is **not** a built-in capability, you must specify the binary’s path inside the Docker container. + +Also, remember that the exact content of the job is hard to know beforehand and you should work with the capability creator to figure out what exactly is required. + +--- + +## Using a New Workflow + +To test a new workflow, you have two options: + +1. Compile the workflow to a WASM binary and upload it to Gist inside the test. +2. Manually upload the binary and specify the workflow URL in the test configuration. + +### Test Uploads the Binary + +For the test to compile and upload the binary, modify your TOML configuration: + +```toml +[workflow_config] + use_chainlink_cli = true + use_existing = false + + [workflow_config.chainlink_cli] + folder_location = "path-to-folder-with-main.go-of-your-workflow" +``` + +### Workflow Configuration + +If your workflow requires configuration, modify the test to create and pass the configuration data to `chainlink-cli`: + +```go +configFile, err := os.CreateTemp("", "config.json") +require.NoError(t, err, "failed to create workflow config file") + +workflowConfig := PoRWorkflowConfig{ + FeedID: feedID, + URL: "https://api.real-time-reserves.verinumus.io/v1/chainlink/proof-of-reserves/TrueUSD", + ConsumerAddress: feedsConsumerAddress.Hex(), +} +``` + +> **Note:** If the workflow is **not configurable**, do not pass configuration data. Instead, pass an empty `[]byte` when compiling or registering it. + +### Workflow Secrets +Currently, workflow secrets are **not supported**. + +### Manual Upload of the Binary + +If you compiled and uploaded the binary yourself, set the following in your configuration: + +```toml +[workflow_config] + use_chainlink_cli = true + use_existing = true + + [workflow_config.existing] + binary_url = "" + config_url = "" +``` + +Both URLs must be accessible by the bootstrap node. + +--- + +## Deployer Address or Deployment Sequence Changes + +By default, the test reuses an existing workflow and configuration. The feed consumer address remains the same **as long as the deployer address (`f39fd6e51aad88f6f4ce6ab8827279cfffb92266`) and contract deployment sequence do not change**. + +If the deployer private key or deployment sequence changes, run the test in **upload mode**: + +```toml +[workflow_config] + use_chainlink_cli = true + use_existing = false + + [workflow_config.chainlink_cli] + folder_location = "path-to-folder-with-main.go-of-your-workflow" +``` + +--- + +## Multiple DONs + +Multiple DONs are **not supported**. A single DON serves as both the **workflow** and **capabilities DON**. + +--- + +## Using a Specific Docker Image for Chainlink Node + +By default, the test builds a Docker image from the current branch: + +```toml +[[nodeset.node_specs]] + [nodeset.node_specs.node] + docker_ctx = "../../.." + docker_file = "plugins/chainlink.Dockerfile" +``` + +To use an existing image, change it to: + +```toml +[[nodeset.node_specs]] + [nodeset.node_specs.node] + image = "image-you-want-to-use" +``` + +Apply this change to **all node entries** in the test configuration. + diff --git a/integration-tests/smoke/capabilities/workflow_test.go b/integration-tests/smoke/capabilities/workflow_test.go index 3a9035103ad..5e4dbbefc33 100644 --- a/integration-tests/smoke/capabilities/workflow_test.go +++ b/integration-tests/smoke/capabilities/workflow_test.go @@ -1,6 +1,7 @@ package capabilities_test import ( + "bufio" "bytes" "cmp" "context" @@ -16,6 +17,7 @@ import ( "net/http" "os" "os/exec" + "path/filepath" "regexp" "slices" "strings" @@ -45,7 +47,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" ns "github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set" "github.com/smartcontractkit/chainlink-testing-framework/lib/docker/test_env" - "github.com/smartcontractkit/chainlink-testing-framework/lib/logging" "github.com/smartcontractkit/chainlink-testing-framework/seth" "github.com/smartcontractkit/chainlink/deployment" @@ -455,6 +456,7 @@ type PoRWorkflowConfig struct { const ( chainlinkCliAssetFile = "cre_v1.0.2_linux_amd64.tar.gz" cronCapabilityAssetFile = "amd64_cron" + ghReadTokenEnvVarName = "GITHUB_READ_TOKEN" ) func downloadAndInstallChainlinkCLI(ghToken string) error { @@ -520,27 +522,36 @@ func validateInputsAndEnvVars(t *testing.T, testConfig *WorkflowTestConfig) { require.True(t, testConfig.WorkflowConfig.UseExising, "if you are not using chainlink-cli you must use an existing workflow") } - ghToken := os.Getenv("GITHUB_API_TOKEN") - _, err := downloadCronCapability(ghToken) - require.NoError(t, err, "failed to download cron capability. Make sure token has content:read permissions to the capabilities repo") - - // TODO this part should ideally happen outside of the test, but due to how our reusable e2e test workflow is structured now - // we cannot execute this part in workflow steps (it doesn't support any pre-execution hooks) + var ghReadToken string + // this is a small hack to avoid changing the reusable workflow if os.Getenv("IS_CI") == "true" { + // This part should ideally happen outside of the test, but due to how our reusable e2e test workflow is structured now + // we cannot execute this part in workflow steps (it doesn't support any pre-execution hooks) require.NotEmpty(t, os.Getenv(ctfconfig.E2E_TEST_CHAINLINK_IMAGE_ENV), "missing env var: "+ctfconfig.E2E_TEST_CHAINLINK_IMAGE_ENV) require.NotEmpty(t, os.Getenv(ctfconfig.E2E_TEST_CHAINLINK_VERSION_ENV), "missing env var: "+ctfconfig.E2E_TEST_CHAINLINK_VERSION_ENV) - if testConfig.WorkflowConfig.UseChainlinkCLI { - err = downloadAndInstallChainlinkCLI(ghToken) - require.NoError(t, err, "failed to download and install chainlink-cli. Make sure token has content:read permissions to the dev-platform repo") - } + // we use this special function to subsitute a placeholder env variable with the actual environment variable name + // it is defined in .github/e2e-tests.yml as '{{ env.GITHUB_API_TOKEN }}' + ghReadToken = ctfconfig.MustReadEnvVar_String(ghReadTokenEnvVarName) + } else { + ghReadToken = os.Getenv(ghReadTokenEnvVarName) } + require.NotEmpty(t, ghReadToken, ghReadTokenEnvVarName+" env var must be set") + _, err := downloadCronCapability(ghReadToken) + require.NoError(t, err, "failed to download cron capability. Make sure token has content:read permissions to the capabilities repo") + if testConfig.WorkflowConfig.UseChainlinkCLI { - require.True(t, isInstalled("chainlink-cli"), "chainlink-cli is required for this test. Please install it, add to path and run again") + if !isInstalled("chainlink-cli") { + err = downloadAndInstallChainlinkCLI(ghReadToken) + require.NoError(t, err, "failed to download and install chainlink-cli. Make sure token has content:read permissions to the dev-platform repo") + } if !testConfig.WorkflowConfig.UseExising { - require.NotEmpty(t, os.Getenv("GITHUB_API_TOKEN"), "GITHUB_API_TOKEN must be set to use chainlink-cli. It requires gist:read and gist:write permissions") + gistWriteToken := os.Getenv("GIST_WRITE_TOKEN") + require.NotEmpty(t, gistWriteToken, "GIST_WRITE_TOKEN must be set to use chainlink-cli to compile workflows. It requires gist:read and gist:write permissions") + err := os.Setenv("GITHUB_API_TOKEN", gistWriteToken) + require.NoError(t, err, "failed to set GITHUB_API_TOKEN env var") } else { require.NotEmpty(t, testConfig.WorkflowConfig.ChainlinkCLI.FolderLocation, "folder_location must be set in the chainlink_cli config") } @@ -718,8 +729,8 @@ func prepareFeedsConsumer(t *testing.T, testLogger zerolog.Logger, ctfEnv *deplo var feedsConsumerAddress common.Address for addrStr, tv := range addresses { if strings.Contains(tv.String(), "FeedConsumer") { - testLogger.Info().Msgf("Deployed FeedConsumer contract at %s", feedsConsumerAddress.Hex()) feedsConsumerAddress = common.HexToAddress(addrStr) + testLogger.Info().Msgf("Deployed FeedConsumer contract at %s", feedsConsumerAddress.Hex()) break } } @@ -977,6 +988,7 @@ func configureNodes(t *testing.T, nodesInfo []NodeInfo, in *WorkflowTestConfig, [OCR2] Enabled = true DatabaseTimeout = '1s' + ContractPollInterval = '1s' [P2P.V2] Enabled = true @@ -1014,6 +1026,7 @@ func configureNodes(t *testing.T, nodesInfo []NodeInfo, in *WorkflowTestConfig, [OCR2] Enabled = true DatabaseTimeout = '1s' + ContractPollInterval = '1s' [P2P.V2] Enabled = true @@ -1346,6 +1359,257 @@ func registerDONAndCapabilities(t *testing.T, capRegAddr common.Address, hashedC require.NoError(t, decodeErr, "failed to add DON to capabilities registry") } +func getLogFileHandles(t *testing.T, l zerolog.Logger, ns *ns.Output) ([]*os.File, error) { + var logFiles []*os.File + + var belongsToCurrentEnv = func(filePath string) bool { + for i, clNode := range ns.CLNodes { + if clNode == nil { + continue + } + + // skip the first node, as it's the bootstrap node + if i == 0 { + continue + } + + if strings.EqualFold(filePath, clNode.Node.ContainerName+".log") { + return true + } + } + return false + } + + logsDir := "logs/docker-" + t.Name() + + fileWalkErr := filepath.Walk(logsDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() && belongsToCurrentEnv(info.Name()) { + file, fileErr := os.Open(path) + if fileErr != nil { + return fmt.Errorf("failed to open file %s: %w", path, fileErr) + } + logFiles = append(logFiles, file) + } + return nil + }) + + expectedLogCount := len(ns.CLNodes) - 1 + if len(logFiles) != expectedLogCount { + l.Warn().Int("Expected", expectedLogCount).Int("Got", len(logFiles)).Msg("Number of log files does not match number of worker nodes. Some logs might be missing.") + } + + if fileWalkErr != nil { + l.Error().Err(fileWalkErr).Msg("Error walking through log files. Will not look for report transmission transaction hashes") + return nil, fileWalkErr + } + + return logFiles, nil +} + +// This function is used to go through Chainlink Node logs and look for entries related to report transmissions. +// Once such a log entry is found, it looks for transaction hash and then it tries to decode the transaction and print the result. +func debugReportTransmissions(logFiles []*os.File, l zerolog.Logger, wsRPCURL string) { + /* + Example log entry: + 2025-01-28T14:44:48.080Z [DEBUG] Node sent transaction multinode@v0.0.0-20250121205514-f73e2f86c23b/transaction_sender.go:180 chainID=1337 logger=EVM.1337.TransactionSender tx={"type":"0x0","chainId":"0x539","nonce":"0x0","to":"0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9","gas":"0x61a80","gasPrice":"0x3b9aca00","maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x0","input":"0x11289565000000000000000000000000a513e6e4b8f2a923d98304ec87f64353c4d5c853000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000010d010f715db03509d388f706e16137722000e26aa650a64ac826ae8e5679cdf57fd96798ed50000000010000000100000a9c593aaed2f5371a5bc0779d1b8ea6f9c7d37bfcbb876a0a9444dbd36f64306466323239353031f39fd6e51aad88f6f4ce6ab8827279cfffb92266000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001018bfe88407000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bb5c162c8000000000000000000000000000000000000000000000000000000006798ed37000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000e700d4c57250eac9dc925c951154c90c1b6017944322fb2075055d8bdbe19000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041561c171b7465e8efef35572ef82adedb49ea71b8344a34a54ce5e853f80ca1ad7d644ebe710728f21ebfc3e2407bd90173244f744faa011c3a57213c8c585de90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004165e6f3623acc43f163a58761655841bfebf3f6b4ea5f8d34c64188036b0ac23037ebbd3854b204ca26d828675395c4b9079ca068d9798326eb8c93f26570a1080100000000000000000000000000000000000000000000000000000000000000","v":"0xa96","r":"0x168547e96e7088c212f85a4e8dddce044bbb2abfd5ccc8a5451fdfcb812c94e5","s":"0x2a735a3df046632c2aaa7e583fe161113f3345002e6c9137bbfa6800a63f28a4","hash":"0x3fc5508310f8deef09a46ad594dcc5dc9ba415319ef1dfa3136335eb9e87ff4d"} version=2.19.0@05c05a9 + + What we are looking for: + "hash":"0x3fc5508310f8deef09a46ad594dcc5dc9ba415319ef1dfa3136335eb9e87ff4d" + */ + reportTransmissionTxHashPattern := regexp.MustCompile(`"hash":"(0x[0-9a-fA-F]+)"`) + + // let's be prudent and assume that in extreme scenario when feed price isn't updated, but + // transmission is still sent, we might have multiple transmissions per node, and if we want + // to avoid blocking on the channel, we need to have a higher buffer + resultsCh := make(chan string, len(logFiles)*4) + + wg := &sync.WaitGroup{} + for _, f := range logFiles { + wg.Add(1) + file := f + + go func() { + defer wg.Done() + + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + + for scanner.Scan() { + jsonLogLine := scanner.Text() + + if !strings.Contains(jsonLogLine, "Node sent transaction") { + continue + } + + match := reportTransmissionTxHashPattern.MatchString(jsonLogLine) + if match { + resultsCh <- reportTransmissionTxHashPattern.FindStringSubmatch(jsonLogLine)[1] + } + } + }() + } + + wg.Wait() + close(resultsCh) + + if len(resultsCh) == 0 { + l.Error().Msg("❌ No report transmissions found in Chainlink Node logs.") + return + } + + // required as Seth prints transaction traces to stdout with debug level + _ = os.Setenv(seth.LogLevelEnvVar, "debug") + + sc, err := seth.NewClientBuilder(). + WithRpcUrl(wsRPCURL). + WithReadOnlyMode(). + WithGethWrappersFolders([]string{"../../../core/gethwrappers/keystone/generated"}). // point Seth to the folder with keystone geth wrappers, so that it can load contract ABIs + Build() + + if err != nil { + l.Error().Err(err).Msg("Failed to create seth client") + return + } + + for txHash := range resultsCh { + l.Info().Msgf("🔍 Tracing report transmission transaction %s", txHash) + // set tracing level to all to trace also successful transactions + sc.Cfg.TracingLevel = seth.TracingLevel_All + tx, _, err := sc.Client.TransactionByHash(context.Background(), common.HexToHash(txHash)) + if err != nil { + l.Warn().Err(err).Msgf("Failed to get transaction by hash %s", txHash) + continue + } + _, decodedErr := sc.DecodeTx(tx) + + if decodedErr != nil { + l.Error().Err(decodedErr).Msgf("Transmission transaction %s failed due to %s", txHash, decodedErr.Error()) + continue + } + } +} + +// this function is used to print debug information from Chainlink Node logs +// it checks whether workflow was executing, OCR was executing and whether reports were sent +// and if they were, it traces each report transmission transaction +func printTestDebug(t *testing.T, l zerolog.Logger, ns *ns.Output, wsRPCURL string) { + logFiles, err := getLogFileHandles(t, l, ns) + if err != nil { + l.Error().Err(err).Msg("Failed to get log file handles. No debug information will be printed") + return + } + + defer func() { + for _, f := range logFiles { + _ = f.Close() + } + }() + + l.Info().Msg("🔍 Debug information from Chainlink Node logs:") + + // assuming one bootstrap node + workflowNodeCount := len(ns.CLNodes) - 1 + if !checkIfWorkflowWasExecuting(logFiles, workflowNodeCount) { + l.Error().Msg("❌ Workflow was not executing") + return + } else { + l.Info().Msg("✅ Workflow was executing") + } + + if !checkIfOCRWasExecuting(logFiles, workflowNodeCount) { + l.Error().Msg("❌ OCR was not executing") + return + } else { + l.Info().Msg("✅ OCR was executing") + } + + if !checkIfAtLeastOneReportWasSent(logFiles, workflowNodeCount) { + l.Error().Msg("❌ Reports were not sent") + return + } else { + l.Info().Msg("✅ Reports were sent") + + // debug report transmissions + debugReportTransmissions(logFiles, l, wsRPCURL) + } +} + +func checkIfLogsHaveText(logFiles []*os.File, bufferSize int, expectedText string, validationFn func(int) bool) bool { + wg := &sync.WaitGroup{} + + resultsCh := make(chan struct{}, bufferSize) + + for _, f := range logFiles { + wg.Add(1) + file := f + + go func() { + defer func() { + wg.Done() + // reset file pointer to the beginning of the file + // so that subsequent reads start from the beginning + _, _ = file.Seek(0, io.SeekStart) + }() + + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + + for scanner.Scan() { + jsonLogLine := scanner.Text() + + if strings.Contains(jsonLogLine, expectedText) { + resultsCh <- struct{}{} + return + } + } + }() + } + + wg.Wait() + close(resultsCh) + + var found int + for range resultsCh { + found++ + } + + return validationFn(found) +} + +func exactCountValidationFn(expected int) func(int) bool { + return func(found int) bool { + return found == expected + } +} + +func checkIfWorkflowWasExecuting(logFiles []*os.File, workflowNodeCount int) bool { + return checkIfLogsHaveText(logFiles, workflowNodeCount, "step request enqueued", exactCountValidationFn(workflowNodeCount)) +} + +func checkIfOCRWasExecuting(logFiles []*os.File, workflowNodeCount int) bool { + return checkIfLogsHaveText(logFiles, workflowNodeCount, "✅ committed outcome", exactCountValidationFn(workflowNodeCount)) +} + +func checkIfAtLeastOneReportWasSent(logFiles []*os.File, workflowNodeCount int) bool { + // we are looking for "Node sent transaction" log entry, which might appear various times in the logs + // but most probably not in the logs of all nodes, since they take turns in sending reports + // our buffer must be large enough to capture all the possible log entries in order to avoid channel blocking + bufferSize := workflowNodeCount * 4 + + return checkIfLogsHaveText(logFiles, bufferSize, "Node sent transaction", func(found int) bool { return found > 0 }) +} + +func logTestInfo(l zerolog.Logger, feedId, workflowName, feedConsumerAddr, forwarderAddr string) { + l.Info().Msg("Test configuration:") + l.Info().Msgf("Feed ID: %s", feedId) + l.Info().Msgf("Workflow name: %s", workflowName) + l.Info().Msgf("FeedConsumer address: %s", feedConsumerAddr) + l.Info().Msgf("KeystoneForwarder address: %s", forwarderAddr) +} + /* !!! ATTENTION !!! @@ -1357,21 +1621,39 @@ and a golden example. Apart from its structure what is currently missing is: - using a mock service to provide the feed data */ func TestKeystoneWithOCR3Workflow(t *testing.T) { - testLogger := logging.GetTestLogger(t) + testLogger := framework.L - // Define and load the test configuration + // Define test configuration donID := uint32(1) workflowName := "abcdefgasd" feedID := "018bfe8840700040000000000000000000000000000000000000000000000000" // without 0x prefix! feedBytes := common.HexToHash(feedID) + // we need to use double-pointers, so that what's captured in the cleanup function is a pointer, not the actual object, + // which is only set later in the test, after the cleanup function is defined + var nodes **ns.Output + var wsRPCURL *string + + // clean up is LIFO, so we need to make sure we execute the debug report transmission after logs are written down + // by function added to clean up by framework.Load() method. + t.Cleanup(func() { + if t.Failed() { + if nodes == nil { + testLogger.Warn().Msg("nodeset output is nil, skipping debug report transmission") + return + } + printTestDebug(t, testLogger, *nodes, *wsRPCURL) + } + }) + + // Load test configuration in, err := framework.Load[WorkflowTestConfig](t) require.NoError(t, err, "couldn't load test config") validateInputsAndEnvVars(t, in) pkey := os.Getenv("PRIVATE_KEY") - // Create a new blockchain network + // Create a new blockchain network and Seth client to interact with it bc, err := blockchain.NewBlockchainNetwork(in.BlockchainA) require.NoError(t, err) @@ -1425,10 +1707,21 @@ func TestKeystoneWithOCR3Workflow(t *testing.T) { // Register the workflow (either via chainlink-cli or by calling the workflow registry directly) registerWorkflow(t, in, sc, capRegAddr, workflowRegistryAddr, feedsConsumerAddress, donID, chainSelector, workflowName, pkey, bc.Nodes[0].HostHTTPUrl) - // Deploy and fund the DON - _, nodesInfo := starAndFundNodes(t, in, bc, sc) + // Log basic information that might help debugging + t.Cleanup(func() { + if t.Failed() { + logTestInfo(testLogger, feedID, workflowName, feedsConsumerAddress.Hex(), forwarderAddress.Hex()) + } + }) + + // Deploy and fund the DON; create OCR3, Gateway and capability-related jobs + ns, nodesInfo := starAndFundNodes(t, in, bc, sc) _, nodeClients := configureNodes(t, nodesInfo, in, bc, capRegAddr, workflowRegistryAddr, forwarderAddress) + // set variables that are needed for the cleanup function, which debugs report transmissions + nodes = &ns + wsRPCURL = &bc.Nodes[0].HostWSUrl + // Deploy OCR3 Capability contract ocr3CapabilityAddress := deployOCR3Capability(t, testLogger, sc) @@ -1441,6 +1734,7 @@ func TestKeystoneWithOCR3Workflow(t *testing.T) { // configure Keystone Forwarder contract configureKeystoneForwarder(t, forwarderAddress, sc, nodesInfo) + // CRUCIAL: Set OCR3 configuration AFTER all the OCR3 jobs are created // Wait for OCR listeners to be ready before setting the configuration. // If the ConfigSet event is missed, OCR protocol will not start. // TODO make it fluent! From c76969447d95f5cf45bc38fb86796d6bbedf316b Mon Sep 17 00:00:00 2001 From: David Cauchi <13139524+davidcauchi@users.noreply.github.com> Date: Thu, 30 Jan 2025 09:44:56 +0100 Subject: [PATCH 05/43] Bump chain-selectors to v1.0.37 (#16127) --- core/scripts/ccip/manual-execution/go.mod | 2 +- core/scripts/ccip/manual-execution/go.sum | 4 ++-- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/scripts/ccip/manual-execution/go.mod b/core/scripts/ccip/manual-execution/go.mod index 91e028c9314..ed13b108889 100644 --- a/core/scripts/ccip/manual-execution/go.mod +++ b/core/scripts/ccip/manual-execution/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/ethereum/go-ethereum v1.11.3 github.com/pkg/errors v0.9.1 - github.com/smartcontractkit/chain-selectors v1.0.35 + github.com/smartcontractkit/chain-selectors v1.0.37 go.uber.org/multierr v1.1.0 golang.org/x/crypto v0.1.0 ) diff --git a/core/scripts/ccip/manual-execution/go.sum b/core/scripts/ccip/manual-execution/go.sum index 3d4ea701977..d03d309b2a8 100644 --- a/core/scripts/ccip/manual-execution/go.sum +++ b/core/scripts/ccip/manual-execution/go.sum @@ -72,8 +72,8 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/smartcontractkit/chain-selectors v1.0.35 h1:k7iJqChFbH10WFpahjDtDJoYyDz4qRNq6ReIB41M8Tg= -github.com/smartcontractkit/chain-selectors v1.0.35/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= +github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXOsnihthONvOPfEOfvbI= +github.com/smartcontractkit/chain-selectors v1.0.37/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 0125129fa0e..5873e44846c 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -314,7 +314,7 @@ require ( github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect - github.com/smartcontractkit/chain-selectors v1.0.36 // indirect + github.com/smartcontractkit/chain-selectors v1.0.37 // indirect github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index d15e5fb0282..b278c538854 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1325,8 +1325,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXOsnihthONvOPfEOfvbI= +github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= diff --git a/deployment/go.mod b/deployment/go.mod index 11703932290..5fe5fdd0c46 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -30,7 +30,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/sethvargo/go-retry v0.2.4 github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix - github.com/smartcontractkit/chain-selectors v1.0.36 + github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 diff --git a/deployment/go.sum b/deployment/go.sum index f03cc9a704b..a1f0fca37c4 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1390,8 +1390,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXOsnihthONvOPfEOfvbI= +github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= diff --git a/go.mod b/go.mod index fe792fec2a5..60ec6f96015 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/shirou/gopsutil/v3 v3.24.3 github.com/shopspring/decimal v1.4.0 - github.com/smartcontractkit/chain-selectors v1.0.36 + github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 diff --git a/go.sum b/go.sum index d00f4406a92..604c6bb500f 100644 --- a/go.sum +++ b/go.sum @@ -1150,8 +1150,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -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/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXOsnihthONvOPfEOfvbI= +github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index d376f8b41b3..b601114447a 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -46,7 +46,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/shopspring/decimal v1.4.0 github.com/slack-go/slack v0.15.0 - github.com/smartcontractkit/chain-selectors v1.0.36 + github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 87031208b92..62cff20ec0f 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1418,8 +1418,8 @@ 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/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXOsnihthONvOPfEOfvbI= +github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 26a726de172..96ba904124e 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -27,7 +27,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.15.0 - github.com/smartcontractkit/chain-selectors v1.0.36 + github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.21 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index f583a85c1a9..90ee782e616 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1405,8 +1405,8 @@ 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/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXOsnihthONvOPfEOfvbI= +github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= From d2c87ca4c71cd5c6da5092e7db6b745f3369f8c9 Mon Sep 17 00:00:00 2001 From: Gabriel Paradiso Date: Thu, 30 Jan 2025 11:33:24 +0100 Subject: [PATCH 06/43] [CAPP-312] handle unconfirmed/confirmed transactions (#16103) * feat: handle unconfirmed/confirmed transactions * chore: add comments and fix lint issues * fix: misleading log when transaction is pending * chore: improve logging message --- core/capabilities/targets/write_target.go | 79 +++++-- .../capabilities/targets/write_target_test.go | 214 ++++++++++++++---- 2 files changed, 228 insertions(+), 65 deletions(-) diff --git a/core/capabilities/targets/write_target.go b/core/capabilities/targets/write_target.go index 3fc51270c86..a312518910b 100644 --- a/core/capabilities/targets/write_target.go +++ b/core/capabilities/targets/write_target.go @@ -5,6 +5,7 @@ import ( "context" "encoding/binary" "encoding/hex" + "errors" "fmt" "math/big" "strings" @@ -44,6 +45,13 @@ type WriteTarget struct { bound bool } +const ( + TransmissionStateNotAttempted uint8 = iota + TransmissionStateSucceeded + TransmissionStateInvalidReceiver + TransmissionStateFailed +) + type TransmissionInfo struct { GasLimit *big.Int InvalidReceiver bool @@ -243,30 +251,21 @@ func (cap *WriteTarget) Execute(ctx context.Context, rawRequest capabilities.Cap } // Check whether value was already transmitted on chain - queryInputs := struct { - Receiver string - WorkflowExecutionID []byte - ReportId []byte - }{ - Receiver: request.Config.Address, - WorkflowExecutionID: rawExecutionID, - ReportId: request.Inputs.SignedReport.ID, - } - var transmissionInfo TransmissionInfo - if err = cap.cr.GetLatestValue(ctx, cap.binding.ReadIdentifier("getTransmissionInfo"), primitives.Unconfirmed, queryInputs, &transmissionInfo); err != nil { - return capabilities.CapabilityResponse{}, fmt.Errorf("failed to getTransmissionInfo latest value: %w", err) + transmissionInfo, err := cap.getTransmissionInfo(ctx, request, rawExecutionID) + if err != nil { + return capabilities.CapabilityResponse{}, err } switch { - case transmissionInfo.State == 0: // NOT_ATTEMPTED + case transmissionInfo.State == TransmissionStateNotAttempted: cap.lggr.Infow("non-empty report - transmission not attempted - attempting to push to txmgr", "request", request, "reportLen", len(request.Inputs.SignedReport.Report), "reportContextLen", len(request.Inputs.SignedReport.Context), "nSignatures", len(request.Inputs.SignedReport.Signatures), "executionID", request.Metadata.WorkflowExecutionID) - case transmissionInfo.State == 1: // SUCCEEDED + case transmissionInfo.State == TransmissionStateSucceeded: cap.lggr.Infow("returning without a transmission attempt - report already onchain ", "executionID", request.Metadata.WorkflowExecutionID) return capabilities.CapabilityResponse{}, nil - case transmissionInfo.State == 2: // INVALID_RECEIVER + case transmissionInfo.State == TransmissionStateInvalidReceiver: cap.lggr.Infow("returning without a transmission attempt - transmission already attempted, receiver was marked as invalid", "executionID", request.Metadata.WorkflowExecutionID) return capabilities.CapabilityResponse{}, nil - case transmissionInfo.State == 3: // FAILED + case transmissionInfo.State == TransmissionStateFailed: receiverGasMinimum := cap.receiverGasMinimum if request.Config.GasLimit != nil { receiverGasMinimum = *request.Config.GasLimit - ForwarderContractLogicGasCost @@ -340,6 +339,35 @@ func (cap *WriteTarget) Execute(ctx context.Context, rawRequest capabilities.Cap continue } switch txStatus { + case commontypes.Pending: + cap.lggr.Debugw("Transaction pending, retrying...", "request", request, "transaction", txID) + // TxStatus Unconfirmed actually means "Confirmed" for the transaction manager, i.e. the transaction has landed on chain but isn't finalized. + case commontypes.Unconfirmed: + transmissionInfo, err = cap.getTransmissionInfo(ctx, request, rawExecutionID) + if err != nil { + return capabilities.CapabilityResponse{}, err + } + + // This is counterintuitive, but the tx manager is currently returning unconfirmed whenever the tx is confirmed + // current implementation here: https://github.com/smartcontractkit/chainlink-framework/blob/main/chains/txmgr/txmgr.go#L697 + // so we need to check if we where able to write to the consumer contract to determine if the transaction was successful + if transmissionInfo.State == TransmissionStateSucceeded { + cap.lggr.Debugw("Transaction confirmed", "request", request, "transaction", txID) + return capabilities.CapabilityResponse{}, nil + } else { + cap.lggr.Errorw("Transaction written to the forwarder, but failed to be written to the consumer contract", "request", request, "transaction", txID, "transmissionState", transmissionInfo.State) + msg := "failed to submit transaction with ID: " + txID.String() + err = cap.emitter.With( + platform.KeyWorkflowID, request.Metadata.WorkflowID, + platform.KeyWorkflowName, request.Metadata.DecodedWorkflowName, + platform.KeyWorkflowOwner, request.Metadata.WorkflowOwner, + platform.KeyWorkflowExecutionID, request.Metadata.WorkflowExecutionID, + ).Emit(ctx, msg) + if err != nil { + cap.lggr.Errorf("failed to send custom message with msg: %s, err: %v", msg, err) + } + return capabilities.CapabilityResponse{}, errors.New("submitted transaction failed") + } case commontypes.Finalized: cap.lggr.Debugw("Transaction finalized", "request", request, "transaction", txID) return capabilities.CapabilityResponse{}, nil @@ -356,7 +384,7 @@ func (cap *WriteTarget) Execute(ctx context.Context, rawRequest capabilities.Cap if err != nil { cap.lggr.Errorf("failed to send custom message with msg: %s, err: %v", msg, err) } - return capabilities.CapabilityResponse{}, fmt.Errorf("submitted transaction failed: %w", err) + return capabilities.CapabilityResponse{}, errors.New("submitted transaction failed") default: cap.lggr.Debugw("Unexpected transaction status", "request", request, "transaction", txID, "status", txStatus) } @@ -371,3 +399,20 @@ func (cap *WriteTarget) RegisterToWorkflow(ctx context.Context, request capabili func (cap *WriteTarget) UnregisterFromWorkflow(ctx context.Context, request capabilities.UnregisterFromWorkflowRequest) error { return nil } + +func (cap *WriteTarget) getTransmissionInfo(ctx context.Context, request Request, rawExecutionID []byte) (*TransmissionInfo, error) { + queryInputs := struct { + Receiver string + WorkflowExecutionID []byte + ReportID []byte + }{ + Receiver: request.Config.Address, + WorkflowExecutionID: rawExecutionID, + ReportID: request.Inputs.SignedReport.ID, + } + var transmissionInfo TransmissionInfo + if err := cap.cr.GetLatestValue(ctx, cap.binding.ReadIdentifier("getTransmissionInfo"), primitives.Unconfirmed, queryInputs, &transmissionInfo); err != nil { + return nil, fmt.Errorf("failed to getTransmissionInfo latest value: %w", err) + } + return &transmissionInfo, nil +} diff --git a/core/capabilities/targets/write_target_test.go b/core/capabilities/targets/write_target_test.go index a702d78cb5d..6fde8387ed9 100644 --- a/core/capabilities/targets/write_target_test.go +++ b/core/capabilities/targets/write_target_test.go @@ -23,9 +23,20 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" ) -func TestWriteTarget(t *testing.T) { +type testHarness struct { + lggr logger.Logger + cw *mocks.ContractWriter + cr *mocks.ContractValueGetter + config *values.Map + validInputs *values.Map + validMetadata capabilities.RequestMetadata + writeTarget *targets.WriteTarget + forwarderAddr string + binding types.BoundContract +} + +func setup(t *testing.T) testHarness { lggr := logger.TestLogger(t) - ctx := context.Background() cw := mocks.NewContractWriter(t) cr := mocks.NewContractValueGetter(t) @@ -85,7 +96,21 @@ func TestWriteTarget(t *testing.T) { cr.On("Bind", mock.Anything, []types.BoundContract{binding}).Return(nil) - cr.EXPECT().GetLatestValue(mock.Anything, binding.ReadIdentifier("getTransmissionInfo"), mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(_ context.Context, _ string, _ primitives.ConfidenceLevel, _, retVal any) { + return testHarness{ + lggr: lggr, + cw: cw, + cr: cr, + config: config, + validInputs: validInputs, + validMetadata: validMetadata, + writeTarget: writeTarget, + forwarderAddr: forwarderAddr, + binding: binding, + } +} +func TestWriteTarget(t *testing.T) { + th := setup(t) + th.cr.EXPECT().GetLatestValue(mock.Anything, th.binding.ReadIdentifier("getTransmissionInfo"), mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(_ context.Context, _ string, _ primitives.ConfidenceLevel, _, retVal any) { transmissionInfo := retVal.(*targets.TransmissionInfo) *transmissionInfo = targets.TransmissionInfo{ GasLimit: big.NewInt(0), @@ -96,93 +121,96 @@ func TestWriteTarget(t *testing.T) { Transmitter: common.HexToAddress("0x0"), } }) - - cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, forwarderAddr, mock.Anything, mock.Anything).Return(nil).Once() - t.Run("succeeds with valid report", func(t *testing.T) { req := capabilities.CapabilityRequest{ - Metadata: validMetadata, - Config: config, - Inputs: validInputs, + Metadata: th.validMetadata, + Config: th.config, + Inputs: th.validInputs, } - cw.On("GetTransactionStatus", mock.Anything, mock.Anything).Return(types.Finalized, nil).Once() + th.cw.On("GetTransactionStatus", mock.Anything, mock.Anything).Return(types.Finalized, nil).Once() + th.cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, th.forwarderAddr, mock.Anything, mock.Anything).Return(nil).Once() - response, err2 := writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + response, err2 := th.writeTarget.Execute(ctx, req) require.NoError(t, err2) require.NotNil(t, response) }) t.Run("fails when ChainWriter's SubmitTransaction returns error", func(t *testing.T) { req := capabilities.CapabilityRequest{ - Metadata: validMetadata, - Config: config, - Inputs: validInputs, + Metadata: th.validMetadata, + Config: th.config, + Inputs: th.validInputs, } - cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, forwarderAddr, mock.Anything, mock.Anything).Return(errors.New("writer error")) + th.cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, th.forwarderAddr, mock.Anything, mock.Anything).Return(errors.New("writer error")) - _, err = writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + _, err := th.writeTarget.Execute(ctx, req) require.Error(t, err) }) t.Run("passes gas limit set on config to the chain writer", func(t *testing.T) { configGasLimit, err2 := values.NewMap(map[string]any{ - "Address": forwarderAddr, + "Address": th.forwarderAddr, "GasLimit": 500000, }) require.NoError(t, err2) req := capabilities.CapabilityRequest{ - Metadata: validMetadata, + Metadata: th.validMetadata, Config: configGasLimit, - Inputs: validInputs, + Inputs: th.validInputs, } meta := types.TxMeta{WorkflowExecutionID: &req.Metadata.WorkflowExecutionID, GasLimit: big.NewInt(500000)} - cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, forwarderAddr, &meta, mock.Anything).Return(types.ErrSettingTransactionGasLimitNotSupported) + th.cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, th.forwarderAddr, &meta, mock.Anything).Return(types.ErrSettingTransactionGasLimitNotSupported) - _, err2 = writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + _, err2 = th.writeTarget.Execute(ctx, req) require.Error(t, err2) }) t.Run("retries without gas limit when ChainWriter's SubmitTransaction returns error due to gas limit not supported", func(t *testing.T) { configGasLimit, err2 := values.NewMap(map[string]any{ - "Address": forwarderAddr, + "Address": th.forwarderAddr, "GasLimit": 500000, }) require.NoError(t, err2) req := capabilities.CapabilityRequest{ - Metadata: validMetadata, + Metadata: th.validMetadata, Config: configGasLimit, - Inputs: validInputs, + Inputs: th.validInputs, } meta := types.TxMeta{WorkflowExecutionID: &req.Metadata.WorkflowExecutionID, GasLimit: big.NewInt(500000)} - cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, forwarderAddr, &meta, mock.Anything).Return(types.ErrSettingTransactionGasLimitNotSupported) + th.cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, th.forwarderAddr, &meta, mock.Anything).Return(types.ErrSettingTransactionGasLimitNotSupported) meta = types.TxMeta{WorkflowExecutionID: &req.Metadata.WorkflowExecutionID} - cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, forwarderAddr, &meta, mock.Anything).Return(nil) + th.cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, th.forwarderAddr, &meta, mock.Anything).Return(nil) - configGasLimit, err = values.NewMap(map[string]any{ - "Address": forwarderAddr, + configGasLimit, err := values.NewMap(map[string]any{ + "Address": th.forwarderAddr, }) require.NoError(t, err) req = capabilities.CapabilityRequest{ - Metadata: validMetadata, + Metadata: th.validMetadata, Config: configGasLimit, - Inputs: validInputs, + Inputs: th.validInputs, } - _, err2 = writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + _, err2 = th.writeTarget.Execute(ctx, req) require.Error(t, err2) }) t.Run("fails when ChainReader's GetLatestValue returns error", func(t *testing.T) { req := capabilities.CapabilityRequest{ - Metadata: validMetadata, - Config: config, - Inputs: validInputs, + Metadata: th.validMetadata, + Config: th.config, + Inputs: th.validInputs, } - cr.EXPECT().GetLatestValue(mock.Anything, binding.ReadIdentifier("getTransmissionInfo"), mock.Anything, mock.Anything, mock.Anything).Return(errors.New("reader error")) + th.cr.EXPECT().GetLatestValue(mock.Anything, th.binding.ReadIdentifier("getTransmissionInfo"), mock.Anything, mock.Anything, mock.Anything).Return(errors.New("reader error")) - _, err = writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + _, err := th.writeTarget.Execute(ctx, req) require.Error(t, err) }) @@ -197,32 +225,38 @@ func TestWriteTarget(t *testing.T) { WorkflowID: "test-id", }, Config: invalidConfig, - Inputs: validInputs, + Inputs: th.validInputs, } - _, err2 = writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + _, err2 = th.writeTarget.Execute(ctx, req) require.Error(t, err2) }) t.Run("fails with nil config", func(t *testing.T) { req := capabilities.CapabilityRequest{ - Metadata: validMetadata, + Metadata: th.validMetadata, Config: nil, - Inputs: validInputs, + Inputs: th.validInputs, } - _, err2 := writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + _, err2 := th.writeTarget.Execute(ctx, req) require.Error(t, err2) }) t.Run("fails with nil inputs", func(t *testing.T) { req := capabilities.CapabilityRequest{ - Metadata: validMetadata, - Config: config, + Metadata: th.validMetadata, + Config: th.config, Inputs: nil, } - _, err2 := writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + _, err2 := th.writeTarget.Execute(ctx, req) require.Error(t, err2) }) +} +func TestWriteTarget_ValidateRequest(t *testing.T) { + th := setup(t) tests := []struct { name string modifyRequest func(*capabilities.CapabilityRequest) @@ -247,13 +281,14 @@ func TestWriteTarget(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req := capabilities.CapabilityRequest{ - Metadata: validMetadata, - Config: config, - Inputs: validInputs, + Metadata: th.validMetadata, + Config: th.config, + Inputs: th.validInputs, } tt.modifyRequest(&req) - _, err := writeTarget.Execute(ctx, req) + ctx := testutils.Context(t) + _, err := th.writeTarget.Execute(ctx, req) if tt.expectedError == "" { require.NoError(t, err) } else { @@ -263,3 +298,86 @@ func TestWriteTarget(t *testing.T) { }) } } + +func TestWriteTarget_UnconfirmedTransaction(t *testing.T) { + t.Run("succeeds when transaction is unconfirmed but transmission succeeded ", func(t *testing.T) { + th := setup(t) + th.cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, th.forwarderAddr, mock.Anything, mock.Anything).Return(nil).Once() + callCount := 0 + th.cr.On("GetLatestValue", mock.Anything, th.binding.ReadIdentifier("getTransmissionInfo"), mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { + transmissionInfo := args.Get(4).(*targets.TransmissionInfo) + if callCount == 0 { + *transmissionInfo = targets.TransmissionInfo{ + GasLimit: big.NewInt(0), + InvalidReceiver: false, + State: targets.TransmissionStateNotAttempted, + Success: false, + TransmissionId: [32]byte{}, + Transmitter: common.HexToAddress("0x0"), + } + } else { + *transmissionInfo = targets.TransmissionInfo{ + GasLimit: big.NewInt(0), + InvalidReceiver: false, + State: targets.TransmissionStateSucceeded, + Success: false, + TransmissionId: [32]byte{}, + Transmitter: common.HexToAddress("0x0"), + } + } + callCount++ + }) + req := capabilities.CapabilityRequest{ + Metadata: th.validMetadata, + Config: th.config, + Inputs: th.validInputs, + } + + th.cw.On("GetTransactionStatus", mock.Anything, mock.Anything).Return(types.Unconfirmed, nil).Once() + + ctx := testutils.Context(t) + response, err2 := th.writeTarget.Execute(ctx, req) + require.NoError(t, err2) + require.NotNil(t, response) + }) + + t.Run("transaction written to the forwarder, but failed to be written to the consumer contract", func(t *testing.T) { + th := setup(t) + th.cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, th.forwarderAddr, mock.Anything, mock.Anything).Return(nil).Once() + callCount := 0 + th.cr.On("GetLatestValue", mock.Anything, th.binding.ReadIdentifier("getTransmissionInfo"), mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { + transmissionInfo := args.Get(4).(*targets.TransmissionInfo) + if callCount == 0 { + *transmissionInfo = targets.TransmissionInfo{ + GasLimit: big.NewInt(0), + InvalidReceiver: false, + State: targets.TransmissionStateNotAttempted, + Success: false, + TransmissionId: [32]byte{}, + Transmitter: common.HexToAddress("0x0"), + } + } else { + *transmissionInfo = targets.TransmissionInfo{ + GasLimit: big.NewInt(0), + InvalidReceiver: false, + State: targets.TransmissionStateFailed, + Success: false, + TransmissionId: [32]byte{}, + Transmitter: common.HexToAddress("0x0"), + } + } + callCount++ + }) + req := capabilities.CapabilityRequest{ + Metadata: th.validMetadata, + Config: th.config, + Inputs: th.validInputs, + } + + th.cw.On("GetTransactionStatus", mock.Anything, mock.Anything).Return(types.Unconfirmed, nil).Once() + ctx := testutils.Context(t) + _, err2 := th.writeTarget.Execute(ctx, req) + require.Error(t, err2) + require.Contains(t, err2.Error(), "submitted transaction failed") + }) +} From 4bb66a771d59695baba73eab33b0058862cc21cd Mon Sep 17 00:00:00 2001 From: dimitris Date: Thu, 30 Jan 2025 12:44:08 +0200 Subject: [PATCH 07/43] Upgrade cl-ccip and adjust ccipReader test (#16139) * fix ccip reader test * upgrade cl-ccip --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- integration-tests/smoke/ccip/ccip_reader_test.go | 11 +++-------- 11 files changed, 18 insertions(+), 23 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 5873e44846c..12a92d20656 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -315,7 +315,7 @@ require ( github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect github.com/smartcontractkit/chain-selectors v1.0.37 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index b278c538854..5dacdc76408 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1329,8 +1329,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= 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.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= diff --git a/deployment/go.mod b/deployment/go.mod index 5fe5fdd0c46..8a75b7f3f53 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -31,7 +31,7 @@ require ( github.com/sethvargo/go-retry v0.2.4 github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix github.com/smartcontractkit/chain-selectors v1.0.37 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b diff --git a/deployment/go.sum b/deployment/go.sum index a1f0fca37c4..ce114a5d41a 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1394,8 +1394,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= 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.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= diff --git a/go.mod b/go.mod index 60ec6f96015..04af3cfdc5d 100644 --- a/go.mod +++ b/go.mod @@ -78,7 +78,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 diff --git a/go.sum b/go.sum index 604c6bb500f..053ed1d8753 100644 --- a/go.sum +++ b/go.sum @@ -1154,8 +1154,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index b601114447a..3dbeb700acc 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -48,7 +48,7 @@ require ( github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-testing-framework/framework v0.4.7 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 62cff20ec0f..4bd1c057c17 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1422,8 +1422,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= 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.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 96ba904124e..fd5211e7b28 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -28,7 +28,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.37 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.21 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.10 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 90ee782e616..16478251fe6 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1409,8 +1409,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250129104727-56a4f7e9e8dc h1:lrdNxbuqC4QV2C4NQFkAF+ZJeL/GxMWJtWrNVYYVYXs= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250129104727-56a4f7e9e8dc/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= 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.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= diff --git a/integration-tests/smoke/ccip/ccip_reader_test.go b/integration-tests/smoke/ccip/ccip_reader_test.go index ac37d593565..b260d6dfc81 100644 --- a/integration-tests/smoke/ccip/ccip_reader_test.go +++ b/integration-tests/smoke/ccip/ccip_reader_test.go @@ -317,7 +317,6 @@ func TestCCIPReader_CommitReportsGTETimestamp(t *testing.T) { require.Eventually(t, func() bool { reports, err = s.reader.CommitReportsGTETimestamp( ctx, - chainD, // Skips first report //nolint:gosec // this won't overflow time.Unix(int64(firstReportTs)+1, 0), @@ -362,7 +361,6 @@ func TestCCIPReader_CommitReportsGTETimestamp_RespectsFinality(t *testing.T) { require.Never(t, func() bool { reports, err = s.reader.CommitReportsGTETimestamp( ctx, - chainD, // Skips first report //nolint:gosec // this won't overflow time.Unix(int64(firstReportTs)+1, 0), @@ -380,7 +378,6 @@ func TestCCIPReader_CommitReportsGTETimestamp_RespectsFinality(t *testing.T) { require.Eventually(t, func() bool { reports, err = s.reader.CommitReportsGTETimestamp( ctx, - chainD, // Skips first report //nolint:gosec // this won't overflow time.Unix(int64(firstReportTs)+1, 0), @@ -443,7 +440,6 @@ func TestCCIPReader_ExecutedMessages(t *testing.T) { executedMsgs, err = s.reader.ExecutedMessages( ctx, chainS1, - chainD, cciptypes.NewSeqNumRange(14, 15), ) require.NoError(t, err) @@ -617,7 +613,7 @@ func TestCCIPReader_GetExpectedNextSequenceNumber(t *testing.T) { 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)) + seqNum, err2 := reader.GetExpectedNextSequenceNumber(ctx, cs(srcChain)) require.NoError(t, err2) require.Equal(t, cciptypes.SeqNum(i+1), seqNum) } @@ -682,7 +678,7 @@ func TestCCIPReader_Nonces(t *testing.T) { } addrQuery = append(addrQuery, utils.RandomAddress().String()) - results, err := s.reader.Nonces(ctx, sourceChain, chainD, addrQuery) + results, err := s.reader.Nonces(ctx, sourceChain, addrQuery) require.NoError(t, err) assert.Len(t, results, len(addrQuery)) for addr, nonce := range addrs { @@ -923,7 +919,7 @@ func benchmarkCommitReports(b *testing.B, logsInsertedFirst int, logsInsertedMat b.ResetTimer() for i := 0; i < b.N; i++ { - reports, err := s.reader.CommitReportsGTETimestamp(ctx, chainD, queryTimestamp, logsInsertedFirst) + reports, err := s.reader.CommitReportsGTETimestamp(ctx, queryTimestamp, logsInsertedFirst) require.NoError(b, err) require.Len(b, reports, logsInsertedFirst) } @@ -1059,7 +1055,6 @@ func benchmarkExecutedMessages(b *testing.B, logsInsertedFirst int, startSeqNum, executedRanges, err := s.reader.ExecutedMessages( ctx, chainS1, - chainD, cciptypes.NewSeqNumRange(startSeqNum, endSeqNum), ) require.NoError(b, err) From 9fc290e842719c0a566b48b2cc6bd4292b1a9e50 Mon Sep 17 00:00:00 2001 From: Gabriel Paradiso Date: Thu, 30 Jan 2025 12:53:04 +0100 Subject: [PATCH 08/43] [CAPPL-499] Enable MaxCompressedBinarySize and MaxDecompressedBinarySize To be configured over job spec (#16138) * chore: enable MaxCompressedBinarySize and MaxDecompressedBinarySize to be configured over job spec * chore: bump chainlink-commons to include latest changes related --- core/capabilities/compute/compute.go | 26 ++++++++++++++++++-------- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- 11 files changed, 33 insertions(+), 23 deletions(-) diff --git a/core/capabilities/compute/compute.go b/core/capabilities/compute/compute.go index e334710a047..62a864675f0 100644 --- a/core/capabilities/compute/compute.go +++ b/core/capabilities/compute/compute.go @@ -389,18 +389,22 @@ func (f *outgoingConnectorFetcherFactory) NewFetcher(log logger.Logger, emitter } const ( - defaultNumWorkers = 3 - defaultMaxMemoryMBs = 128 - defaultMaxTickInterval = 100 * time.Millisecond - defaultMaxTimeout = 10 * time.Second + defaultNumWorkers = 3 + defaultMaxMemoryMBs = 128 + defaultMaxTickInterval = 100 * time.Millisecond + defaultMaxTimeout = 10 * time.Second + defaultMaxCompressedBinarySize = 20 * 1024 * 1024 // 20 MB + defaultMaxDecompressedBinarySize = 100 * 1024 * 1024 // 100 MB ) type Config struct { webapi.ServiceConfig - NumWorkers int - MaxMemoryMBs uint64 - MaxTimeout time.Duration - MaxTickInterval time.Duration + NumWorkers int + MaxMemoryMBs uint64 + MaxTimeout time.Duration + MaxTickInterval time.Duration + MaxCompressedBinarySize uint64 + MaxDecompressedBinarySize uint64 } func (c *Config) ApplyDefaults() { @@ -416,6 +420,12 @@ func (c *Config) ApplyDefaults() { if c.MaxTickInterval == 0 { c.MaxTickInterval = defaultMaxTickInterval } + if c.MaxCompressedBinarySize == 0 { + c.MaxCompressedBinarySize = uint64(defaultMaxCompressedBinarySize) + } + if c.MaxDecompressedBinarySize == 0 { + c.MaxDecompressedBinarySize = uint64(defaultMaxDecompressedBinarySize) + } } func NewAction( diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 12a92d20656..f55202b4aea 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -34,7 +34,7 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/libocr v0.0.0-20241223215956-e5b78d8e3919 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 5dacdc76408..fd653a96662 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1333,8 +1333,8 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= 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.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/deployment/go.mod b/deployment/go.mod index 8a75b7f3f53..f6797ca8dcb 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -33,7 +33,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20250121222331-a7010b4b8ce5 diff --git a/deployment/go.sum b/deployment/go.sum index ce114a5d41a..7c5ac0ab32b 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1398,8 +1398,8 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= 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.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/go.mod b/go.mod index 04af3cfdc5d..11e8a3b8624 100644 --- a/go.mod +++ b/go.mod @@ -79,7 +79,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 github.com/smartcontractkit/chainlink-feeds v0.1.1 diff --git a/go.sum b/go.sum index 053ed1d8753..d1e88d5d0c2 100644 --- a/go.sum +++ b/go.sum @@ -1156,8 +1156,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 3dbeb700acc..f1c4123ccfa 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -49,7 +49,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-testing-framework/framework v0.4.7 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 4bd1c057c17..a18c8e51e47 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1426,8 +1426,8 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= 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.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index fd5211e7b28..768489287b8 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -29,7 +29,7 @@ require ( github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.21 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.10 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.2 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 16478251fe6..cfed477edfa 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1413,8 +1413,8 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= 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.2-0.20250127125541-a8fa42cc0f36 h1:dytZPggag6auyzmbhpIDmkHu7KrflIBEhLLec4/xFIk= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250127125541-a8fa42cc0f36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= From c9671d859dc2f9a8fad2becdc0e61c9d687a5334 Mon Sep 17 00:00:00 2001 From: Simson Date: Thu, 30 Jan 2025 18:18:50 +0530 Subject: [PATCH 09/43] update price min for bsc to 1 gwei (#16115) * update price min for bsc to 1 gwei * docs update * removed repeated overrides --- ccip/config/evm/BSC_Mainnet.toml | 24 -------------------- ccip/config/evm/BSC_Testnet.toml | 27 ----------------------- docs/CONFIG.md | 6 ++--- evm/config/toml/defaults/BSC_Mainnet.toml | 4 +--- evm/config/toml/defaults/BSC_Testnet.toml | 2 +- 5 files changed, 5 insertions(+), 58 deletions(-) diff --git a/ccip/config/evm/BSC_Mainnet.toml b/ccip/config/evm/BSC_Mainnet.toml index e95f0af1eb7..45bc2cb598f 100644 --- a/ccip/config/evm/BSC_Mainnet.toml +++ b/ccip/config/evm/BSC_Mainnet.toml @@ -4,27 +4,3 @@ ChainID = '56' # Keeping this >> 11 because it's not expensive and gives us a safety margin FinalityDepth = 50 -FinalityTagEnabled = true -LinkContractAddress = '0x404460C6A5EdE2D891e8297795264fDe62ADBB75' -LogPollInterval = '3s' -NoNewHeadsThreshold = '30s' -RPCBlockQueryDelay = 2 -NoNewFinalizedHeadsThreshold = '45s' - -[GasEstimator] -PriceDefault = '5 gwei' -# Set to the BSC node's default Eth.Miner.GasPrice config -PriceMin = '3 gwei' -# 15s delay since feeds update every minute in volatile situations -BumpThreshold = 5 - -[GasEstimator.BlockHistory] -BlockHistorySize = 24 - -[OCR] -DatabaseTimeout = '2s' -ContractTransmitterTransmitTimeout = '2s' -ObservationGracePeriod = '500ms' - -[NodePool] -SyncThreshold = 10 diff --git a/ccip/config/evm/BSC_Testnet.toml b/ccip/config/evm/BSC_Testnet.toml index b27a877812b..9ed37c88a82 100644 --- a/ccip/config/evm/BSC_Testnet.toml +++ b/ccip/config/evm/BSC_Testnet.toml @@ -4,30 +4,3 @@ ChainID = '97' # Keeping this >> 11 because it's not expensive and gives us a safety margin FinalityDepth = 50 -FinalityTagEnabled = true -LinkContractAddress = '0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06' -LogPollInterval = '3s' -NoNewHeadsThreshold = '30s' -RPCBlockQueryDelay = 2 -NoNewFinalizedHeadsThreshold = '40s' - -[GasEstimator] -PriceDefault = '5 gwei' -# 15s delay since feeds update every minute in volatile situations -BumpThreshold = 5 - -[GasEstimator.BlockHistory] -BlockHistorySize = 24 - -[HeadTracker] -HistoryDepth = 100 -SamplingInterval = '1s' -FinalityTagBypass = false - -[OCR] -DatabaseTimeout = '2s' -ContractTransmitterTransmitTimeout = '2s' -ObservationGracePeriod = '500ms' - -[NodePool] -SyncThreshold = 10 diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 19c3d9fbb4d..2bc61cd64aa 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -2989,9 +2989,9 @@ Enabled = true [GasEstimator] Mode = 'BlockHistory' -PriceDefault = '5 gwei' +PriceDefault = '1 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' -PriceMin = '3 gwei' +PriceMin = '1 gwei' LimitDefault = 500000 LimitMax = 500000 LimitMultiplier = '1' @@ -3419,7 +3419,7 @@ Enabled = true [GasEstimator] Mode = 'BlockHistory' -PriceDefault = '5 gwei' +PriceDefault = '1 gwei' PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' PriceMin = '1 gwei' LimitDefault = 500000 diff --git a/evm/config/toml/defaults/BSC_Mainnet.toml b/evm/config/toml/defaults/BSC_Mainnet.toml index 710ef34d309..357bd551998 100644 --- a/evm/config/toml/defaults/BSC_Mainnet.toml +++ b/evm/config/toml/defaults/BSC_Mainnet.toml @@ -11,9 +11,7 @@ FinalizedBlockOffset = 2 NoNewFinalizedHeadsThreshold = '45s' [GasEstimator] -PriceDefault = '5 gwei' -# Set to the BSC node's default Eth.Miner.GasPrice config -PriceMin = '3 gwei' +PriceDefault = '1 gwei' # 15s delay since feeds update every minute in volatile situations BumpThreshold = 5 diff --git a/evm/config/toml/defaults/BSC_Testnet.toml b/evm/config/toml/defaults/BSC_Testnet.toml index 95eef689d00..f2fc6044b6f 100644 --- a/evm/config/toml/defaults/BSC_Testnet.toml +++ b/evm/config/toml/defaults/BSC_Testnet.toml @@ -11,7 +11,7 @@ FinalizedBlockOffset = 2 NoNewFinalizedHeadsThreshold = '40s' [GasEstimator] -PriceDefault = '5 gwei' +PriceDefault = '1 gwei' # 15s delay since feeds update every minute in volatile situations BumpThreshold = 5 From 5db1008cca6615c9d0a6b33adab6ec50b6ef754b Mon Sep 17 00:00:00 2001 From: Brandon West <3317895+Bwest981@users.noreply.github.com> Date: Thu, 30 Jan 2025 09:54:10 -0500 Subject: [PATCH 10/43] Bump version and update CHANGELOG for core v2.20.0 (#16020) Signed-off-by: bwest981 <3317895+Bwest981@users.noreply.github.com> --- .changeset/afraid-houses-learn.md | 5 - .changeset/beige-geckos-explode.md | 5 - .changeset/big-camels-report.md | 5 - .changeset/brave-cooks-itch.md | 5 - .changeset/breezy-kings-clean.md | 5 - .changeset/bright-keys-whisper.md | 5 - .changeset/chilled-papayas-swim.md | 5 - .changeset/chilled-suits-do.md | 5 - .changeset/chilly-stingrays-press.md | 5 - .changeset/clean-files-beg.md | 5 - .changeset/clever-knives-tap.md | 5 - .changeset/cold-coats-battle.md | 5 - .changeset/cold-pillows-sleep.md | 5 - .changeset/cool-penguins-raise.md | 5 - .changeset/cuddly-turtles-arrive.md | 5 - .changeset/cyan-ladybugs-check.md | 5 - .changeset/dull-readers-rush.md | 5 - .changeset/eight-meals-march.md | 7 -- .changeset/eight-tigers-march.md | 5 - .changeset/eighty-geckos-switch.md | 5 - .changeset/eleven-cheetahs-care.md | 7 -- .changeset/five-beds-wait.md | 5 - .changeset/five-gifts-end.md | 5 - .changeset/fluffy-lizards-laugh.md | 5 - .changeset/forty-foxes-rescue.md | 5 - .changeset/fresh-lobsters-fly.md | 5 - .changeset/friendly-tigers-argue.md | 5 - .changeset/fuzzy-hairs-appear.md | 5 - .changeset/fuzzy-yaks-deny.md | 5 - .changeset/giant-eels-jump.md | 5 - .changeset/gorgeous-ants-promise.md | 5 - .changeset/great-peaches-walk.md | 5 - .changeset/hot-cats-enjoy.md | 5 - .changeset/hot-islands-dress.md | 5 - .changeset/kind-parents-jump.md | 11 -- .changeset/large-ants-occur.md | 5 - .changeset/large-fishes-enjoy.md | 5 - .changeset/late-doors-battle.md | 5 - .changeset/late-hornets-yell.md | 5 - .changeset/late-seals-battle.md | 5 - .changeset/light-trains-chew.md | 5 - .changeset/long-apples-fold.md | 5 - .changeset/loud-birds-remain.md | 5 - .changeset/many-crews-wave.md | 5 - .changeset/many-nails-explode.md | 5 - .changeset/mean-dots-move.md | 5 - .changeset/mean-knives-knock.md | 5 - .changeset/mean-ravens-stare.md | 5 - .changeset/metal-houses-approve.md | 5 - .changeset/poor-adults-tie.md | 5 - .changeset/popular-rules-live.md | 5 - .changeset/rotten-books-cross.md | 5 - .changeset/shaggy-carpets-deliver.md | 5 - .changeset/sharp-llamas-compete.md | 5 - .changeset/shiny-owls-destroy.md | 6 - .changeset/silver-avocados-buy.md | 5 - .changeset/silver-books-grab.md | 5 - .changeset/six-camels-smell.md | 5 + .changeset/six-coins-mix.md | 5 - .changeset/soft-rivers-care.md | 5 - .changeset/sour-hairs-cross.md | 5 - .changeset/spotty-knives-smile.md | 5 - .changeset/spotty-seals-give.md | 5 - .changeset/tall-falcons-yawn.md | 5 - .changeset/thick-vans-tickle.md | 5 - .changeset/thin-cats-try.md | 5 - .changeset/thin-emus-wait.md | 5 - .changeset/tiny-kangaroos-switch.md | 5 - .changeset/tricky-clouds-move.md | 5 - .changeset/warm-panthers-stare.md | 5 - .changeset/wet-bags-clean.md | 5 - .changeset/wild-cats-think.md | 5 - .changeset/wild-planes-mix.md | 5 - .changeset/wise-buttons-fry.md | 5 - .changeset/yellow-brooms-leave.md | 5 - CHANGELOG.md | 165 +++++++++++++++++++++++++++ package.json | 2 +- 77 files changed, 171 insertions(+), 382 deletions(-) delete mode 100644 .changeset/afraid-houses-learn.md delete mode 100644 .changeset/beige-geckos-explode.md delete mode 100644 .changeset/big-camels-report.md delete mode 100644 .changeset/brave-cooks-itch.md delete mode 100644 .changeset/breezy-kings-clean.md delete mode 100644 .changeset/bright-keys-whisper.md delete mode 100644 .changeset/chilled-papayas-swim.md delete mode 100644 .changeset/chilled-suits-do.md delete mode 100644 .changeset/chilly-stingrays-press.md delete mode 100644 .changeset/clean-files-beg.md delete mode 100644 .changeset/clever-knives-tap.md delete mode 100644 .changeset/cold-coats-battle.md delete mode 100644 .changeset/cold-pillows-sleep.md delete mode 100644 .changeset/cool-penguins-raise.md delete mode 100644 .changeset/cuddly-turtles-arrive.md delete mode 100644 .changeset/cyan-ladybugs-check.md delete mode 100644 .changeset/dull-readers-rush.md delete mode 100644 .changeset/eight-meals-march.md delete mode 100644 .changeset/eight-tigers-march.md delete mode 100644 .changeset/eighty-geckos-switch.md delete mode 100644 .changeset/eleven-cheetahs-care.md delete mode 100644 .changeset/five-beds-wait.md delete mode 100644 .changeset/five-gifts-end.md delete mode 100644 .changeset/fluffy-lizards-laugh.md delete mode 100644 .changeset/forty-foxes-rescue.md delete mode 100644 .changeset/fresh-lobsters-fly.md delete mode 100644 .changeset/friendly-tigers-argue.md delete mode 100644 .changeset/fuzzy-hairs-appear.md delete mode 100644 .changeset/fuzzy-yaks-deny.md delete mode 100644 .changeset/giant-eels-jump.md delete mode 100644 .changeset/gorgeous-ants-promise.md delete mode 100644 .changeset/great-peaches-walk.md delete mode 100644 .changeset/hot-cats-enjoy.md delete mode 100644 .changeset/hot-islands-dress.md delete mode 100644 .changeset/kind-parents-jump.md delete mode 100644 .changeset/large-ants-occur.md delete mode 100644 .changeset/large-fishes-enjoy.md delete mode 100644 .changeset/late-doors-battle.md delete mode 100644 .changeset/late-hornets-yell.md delete mode 100644 .changeset/late-seals-battle.md delete mode 100644 .changeset/light-trains-chew.md delete mode 100644 .changeset/long-apples-fold.md delete mode 100644 .changeset/loud-birds-remain.md delete mode 100644 .changeset/many-crews-wave.md delete mode 100644 .changeset/many-nails-explode.md delete mode 100644 .changeset/mean-dots-move.md delete mode 100644 .changeset/mean-knives-knock.md delete mode 100644 .changeset/mean-ravens-stare.md delete mode 100644 .changeset/metal-houses-approve.md delete mode 100644 .changeset/poor-adults-tie.md delete mode 100644 .changeset/popular-rules-live.md delete mode 100644 .changeset/rotten-books-cross.md delete mode 100644 .changeset/shaggy-carpets-deliver.md delete mode 100644 .changeset/sharp-llamas-compete.md delete mode 100644 .changeset/shiny-owls-destroy.md delete mode 100644 .changeset/silver-avocados-buy.md delete mode 100644 .changeset/silver-books-grab.md create mode 100644 .changeset/six-camels-smell.md delete mode 100644 .changeset/six-coins-mix.md delete mode 100644 .changeset/soft-rivers-care.md delete mode 100644 .changeset/sour-hairs-cross.md delete mode 100644 .changeset/spotty-knives-smile.md delete mode 100644 .changeset/spotty-seals-give.md delete mode 100644 .changeset/tall-falcons-yawn.md delete mode 100644 .changeset/thick-vans-tickle.md delete mode 100644 .changeset/thin-cats-try.md delete mode 100644 .changeset/thin-emus-wait.md delete mode 100644 .changeset/tiny-kangaroos-switch.md delete mode 100644 .changeset/tricky-clouds-move.md delete mode 100644 .changeset/warm-panthers-stare.md delete mode 100644 .changeset/wet-bags-clean.md delete mode 100644 .changeset/wild-cats-think.md delete mode 100644 .changeset/wild-planes-mix.md delete mode 100644 .changeset/wise-buttons-fry.md delete mode 100644 .changeset/yellow-brooms-leave.md diff --git a/.changeset/afraid-houses-learn.md b/.changeset/afraid-houses-learn.md deleted file mode 100644 index 3d161965bae..00000000000 --- a/.changeset/afraid-houses-learn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#updated use real contracts in ccipreader_tests where possible diff --git a/.changeset/beige-geckos-explode.md b/.changeset/beige-geckos-explode.md deleted file mode 100644 index 9f06a9c989b..00000000000 --- a/.changeset/beige-geckos-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#updated Gracefully fail if CL_DATABASE_URL is not set. diff --git a/.changeset/big-camels-report.md b/.changeset/big-camels-report.md deleted file mode 100644 index f81f66b9138..00000000000 --- a/.changeset/big-camels-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#bugfix fix non-idempotent loopp registry.Register diff --git a/.changeset/brave-cooks-itch.md b/.changeset/brave-cooks-itch.md deleted file mode 100644 index 1ed3dd7e117..00000000000 --- a/.changeset/brave-cooks-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#updated feat(job-distributor): support tron chain type on sync diff --git a/.changeset/breezy-kings-clean.md b/.changeset/breezy-kings-clean.md deleted file mode 100644 index b72a0689019..00000000000 --- a/.changeset/breezy-kings-clean.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Potential bug introduced from chain selector refactor, not causing issue now since only EVM is used, but need to fix #bugfix diff --git a/.changeset/bright-keys-whisper.md b/.changeset/bright-keys-whisper.md deleted file mode 100644 index 16bf56b2ac9..00000000000 --- a/.changeset/bright-keys-whisper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -allow different decimals on different chains for token pools diff --git a/.changeset/chilled-papayas-swim.md b/.changeset/chilled-papayas-swim.md deleted file mode 100644 index e2f2b536514..00000000000 --- a/.changeset/chilled-papayas-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#removed Remove duplicated testing util for p2p_key only. diff --git a/.changeset/chilled-suits-do.md b/.changeset/chilled-suits-do.md deleted file mode 100644 index 611fe95d159..00000000000 --- a/.changeset/chilled-suits-do.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Updated the Solana TXM compute unit limit estimation feature to use the max 1.4M compute unit limit for simulation and enable SigVerify #updated diff --git a/.changeset/chilly-stingrays-press.md b/.changeset/chilly-stingrays-press.md deleted file mode 100644 index 1fe2e80f2b0..00000000000 --- a/.changeset/chilly-stingrays-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Removing ccip-tests/\* dependencies and moving ccip tests under a directory in smoke diff --git a/.changeset/clean-files-beg.md b/.changeset/clean-files-beg.md deleted file mode 100644 index 1357a044cb0..00000000000 --- a/.changeset/clean-files-beg.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Adding OCR3 promwrapper to LLO #internal diff --git a/.changeset/clever-knives-tap.md b/.changeset/clever-knives-tap.md deleted file mode 100644 index 8683e89f77d..00000000000 --- a/.changeset/clever-knives-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#added Sei config and error mapping diff --git a/.changeset/cold-coats-battle.md b/.changeset/cold-coats-battle.md deleted file mode 100644 index 1a72d025bde..00000000000 --- a/.changeset/cold-coats-battle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal minor rename of various gethwrappers diff --git a/.changeset/cold-pillows-sleep.md b/.changeset/cold-pillows-sleep.md deleted file mode 100644 index 45e4e999111..00000000000 --- a/.changeset/cold-pillows-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Extract EVM MultiNode to chainlink-framework. #internal diff --git a/.changeset/cool-penguins-raise.md b/.changeset/cool-penguins-raise.md deleted file mode 100644 index c47839be310..00000000000 --- a/.changeset/cool-penguins-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#updated Remove custom ed25519 private to public key conversion. diff --git a/.changeset/cuddly-turtles-arrive.md b/.changeset/cuddly-turtles-arrive.md deleted file mode 100644 index 81ceed3e8ff..00000000000 --- a/.changeset/cuddly-turtles-arrive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal adding solana devnet to ccip deployment diff --git a/.changeset/cyan-ladybugs-check.md b/.changeset/cyan-ladybugs-check.md deleted file mode 100644 index d430890001a..00000000000 --- a/.changeset/cyan-ladybugs-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -validates response from gateway in workflow/fetcher diff --git a/.changeset/dull-readers-rush.md b/.changeset/dull-readers-rush.md deleted file mode 100644 index 3b6f2ae8758..00000000000 --- a/.changeset/dull-readers-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Reporting number of OCR3 instances running using promwrapper #internal diff --git a/.changeset/eight-meals-march.md b/.changeset/eight-meals-march.md deleted file mode 100644 index f2439280063..00000000000 --- a/.changeset/eight-meals-march.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"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/eight-tigers-march.md b/.changeset/eight-tigers-march.md deleted file mode 100644 index 611628f2ef6..00000000000 --- a/.changeset/eight-tigers-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#added Adding 5 chains (B^2, BoB, Berachain, Unichain, Worldchain configs) diff --git a/.changeset/eighty-geckos-switch.md b/.changeset/eighty-geckos-switch.md deleted file mode 100644 index b67dfb0ec79..00000000000 --- a/.changeset/eighty-geckos-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Reduce PriceMin on Avalanche to 1 gwei #nops diff --git a/.changeset/eleven-cheetahs-care.md b/.changeset/eleven-cheetahs-care.md deleted file mode 100644 index 2ac6417b342..00000000000 --- a/.changeset/eleven-cheetahs-care.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"chainlink": patch ---- - -Add panic recovery to wsrpc mercury client - -- Should help to make nodes running wsrpc v0.8.2 more stable #bugfix diff --git a/.changeset/five-beds-wait.md b/.changeset/five-beds-wait.md deleted file mode 100644 index 36ee14f49b6..00000000000 --- a/.changeset/five-beds-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#bugfix Add chaintype.ChainZircuit to chaintypes with rollup support in L1 oracle to prevent a nil L1 oracle being used for Zircuit's gas estimator diff --git a/.changeset/five-gifts-end.md b/.changeset/five-gifts-end.md deleted file mode 100644 index dd13fda476d..00000000000 --- a/.changeset/five-gifts-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#added stream job delete capability diff --git a/.changeset/fluffy-lizards-laugh.md b/.changeset/fluffy-lizards-laugh.md deleted file mode 100644 index 3d38170c2d8..00000000000 --- a/.changeset/fluffy-lizards-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Changed RMNRemote and RMNHome parameter f to fObserve and fSign #updated diff --git a/.changeset/forty-foxes-rescue.md b/.changeset/forty-foxes-rescue.md deleted file mode 100644 index 9456ebe5e36..00000000000 --- a/.changeset/forty-foxes-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#removed Remove unused ocr1 key files. diff --git a/.changeset/fresh-lobsters-fly.md b/.changeset/fresh-lobsters-fly.md deleted file mode 100644 index 12b9c317dcb..00000000000 --- a/.changeset/fresh-lobsters-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal Refactored ChainComponents tests to run in parallel diff --git a/.changeset/friendly-tigers-argue.md b/.changeset/friendly-tigers-argue.md deleted file mode 100644 index 25aff7e13ae..00000000000 --- a/.changeset/friendly-tigers-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal change gethwrapper to allow for foundry based gethwrapper generation diff --git a/.changeset/fuzzy-hairs-appear.md b/.changeset/fuzzy-hairs-appear.md deleted file mode 100644 index a4797462546..00000000000 --- a/.changeset/fuzzy-hairs-appear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Prometheus observability layer added to OCR3 Reporting Plugins #internal diff --git a/.changeset/fuzzy-yaks-deny.md b/.changeset/fuzzy-yaks-deny.md deleted file mode 100644 index 6de0c8d096c..00000000000 --- a/.changeset/fuzzy-yaks-deny.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#added Lens Sepolia config diff --git a/.changeset/giant-eels-jump.md b/.changeset/giant-eels-jump.md deleted file mode 100644 index 5ab8ca875ca..00000000000 --- a/.changeset/giant-eels-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Add error handling for Arbitrum RPC server timeouts. #added diff --git a/.changeset/gorgeous-ants-promise.md b/.changeset/gorgeous-ants-promise.md deleted file mode 100644 index 117bc9a85a9..00000000000 --- a/.changeset/gorgeous-ants-promise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Updated TXM abandon transaction functionality to drop related attempts. #updated diff --git a/.changeset/great-peaches-walk.md b/.changeset/great-peaches-walk.md deleted file mode 100644 index 30e7446bb0c..00000000000 --- a/.changeset/great-peaches-walk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -fix reported evm node states diff --git a/.changeset/hot-cats-enjoy.md b/.changeset/hot-cats-enjoy.md deleted file mode 100644 index 15fc98d9d44..00000000000 --- a/.changeset/hot-cats-enjoy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#added beholder metric to monitor TXMv2 transactions. diff --git a/.changeset/hot-islands-dress.md b/.changeset/hot-islands-dress.md deleted file mode 100644 index 82e34ecf42b..00000000000 --- a/.changeset/hot-islands-dress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal refactor: inject ocr secrets via env instead of config diff --git a/.changeset/kind-parents-jump.md b/.changeset/kind-parents-jump.md deleted file mode 100644 index e633f1af1fe..00000000000 --- a/.changeset/kind-parents-jump.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"chainlink": patch ---- - -Add two new metrics for monitoring LLO transmitter health #added - -`llo_mercurytransmitter_concurrent_transmit_gauge` -Gauge that measures the number of transmit threads currently waiting on a remote transmit call. You may wish to alert if this exceeds some number for a given period of time, or if it ever reaches its max. - -`llo_mercurytransmitter_concurrent_delete_gauge` -Gauge that measures the number of delete threads currently waiting on a delete call to the DB. You may wish to alert if this exceeds some number for a given period of time, or if it ever reaches its max. diff --git a/.changeset/large-ants-occur.md b/.changeset/large-ants-occur.md deleted file mode 100644 index 81bf4ed5728..00000000000 --- a/.changeset/large-ants-occur.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -add reorg detection for Solana TXM. #added diff --git a/.changeset/large-fishes-enjoy.md b/.changeset/large-fishes-enjoy.md deleted file mode 100644 index 201267e8b64..00000000000 --- a/.changeset/large-fishes-enjoy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Fix logic for mapping affected files in CI that affects golangci-lint execution diff --git a/.changeset/late-doors-battle.md b/.changeset/late-doors-battle.md deleted file mode 100644 index 8ec64b9048e..00000000000 --- a/.changeset/late-doors-battle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Fix TransactionSender go routine leak. #bugfix diff --git a/.changeset/late-hornets-yell.md b/.changeset/late-hornets-yell.md deleted file mode 100644 index 7d04500cc77..00000000000 --- a/.changeset/late-hornets-yell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#updated Bump chainlink-common version. diff --git a/.changeset/late-seals-battle.md b/.changeset/late-seals-battle.md deleted file mode 100644 index 194aa4f380e..00000000000 --- a/.changeset/late-seals-battle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Update deployment address book to support non-evm chains diff --git a/.changeset/light-trains-chew.md b/.changeset/light-trains-chew.md deleted file mode 100644 index edbb5a7f7bc..00000000000 --- a/.changeset/light-trains-chew.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Refactor chain ID logic in plugin to be chain agnostic #added diff --git a/.changeset/long-apples-fold.md b/.changeset/long-apples-fold.md deleted file mode 100644 index ba3e731951f..00000000000 --- a/.changeset/long-apples-fold.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -DEVSVCS-958: fix automation v2.3 batching bug #bugfix diff --git a/.changeset/loud-birds-remain.md b/.changeset/loud-birds-remain.md deleted file mode 100644 index eb1e8f8a9ca..00000000000 --- a/.changeset/loud-birds-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#internal Add unexposed shell cmd for updating a bridge diff --git a/.changeset/many-crews-wave.md b/.changeset/many-crews-wave.md deleted file mode 100644 index 328a00e2f48..00000000000 --- a/.changeset/many-crews-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal refactor update nodes changeset to support mcms diff --git a/.changeset/many-nails-explode.md b/.changeset/many-nails-explode.md deleted file mode 100644 index 43644ef3ec4..00000000000 --- a/.changeset/many-nails-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#added core configs diff --git a/.changeset/mean-dots-move.md b/.changeset/mean-dots-move.md deleted file mode 100644 index 1169d8379e9..00000000000 --- a/.changeset/mean-dots-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Add config var Mercury.Transmitter.TransmitConcurrency #added diff --git a/.changeset/mean-knives-knock.md b/.changeset/mean-knives-knock.md deleted file mode 100644 index e04ba4d083f..00000000000 --- a/.changeset/mean-knives-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#updated chainconfig: show chain type next to key bundle id in UI diff --git a/.changeset/mean-ravens-stare.md b/.changeset/mean-ravens-stare.md deleted file mode 100644 index 6b481ae4520..00000000000 --- a/.changeset/mean-ravens-stare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal add versioned geth wrappers for keystone prod contracts diff --git a/.changeset/metal-houses-approve.md b/.changeset/metal-houses-approve.md deleted file mode 100644 index 6768c50767e..00000000000 --- a/.changeset/metal-houses-approve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Added TxExpirationRebroadcast feature and config for Solana TXM. #added diff --git a/.changeset/poor-adults-tie.md b/.changeset/poor-adults-tie.md deleted file mode 100644 index 5d1e7b7fc56..00000000000 --- a/.changeset/poor-adults-tie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#updated Explicitly use protoc installed in the makefile. diff --git a/.changeset/popular-rules-live.md b/.changeset/popular-rules-live.md deleted file mode 100644 index 2d996a28dc2..00000000000 --- a/.changeset/popular-rules-live.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Fixes a race condition with the Finalizer when clearing txs #bugfix diff --git a/.changeset/rotten-books-cross.md b/.changeset/rotten-books-cross.md deleted file mode 100644 index 95231ec47f2..00000000000 --- a/.changeset/rotten-books-cross.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Support multiple streamIDs in stream specs #added diff --git a/.changeset/shaggy-carpets-deliver.md b/.changeset/shaggy-carpets-deliver.md deleted file mode 100644 index 676ad2fb861..00000000000 --- a/.changeset/shaggy-carpets-deliver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#removed dead transmission tests diff --git a/.changeset/sharp-llamas-compete.md b/.changeset/sharp-llamas-compete.md deleted file mode 100644 index 76808dbdda4..00000000000 --- a/.changeset/sharp-llamas-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#bugfix Fix missing Tron handler diff --git a/.changeset/shiny-owls-destroy.md b/.changeset/shiny-owls-destroy.md deleted file mode 100644 index d132d6dbff8..00000000000 --- a/.changeset/shiny-owls-destroy.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"chainlink": patch ---- - -Logging improvements for LLO -#internal diff --git a/.changeset/silver-avocados-buy.md b/.changeset/silver-avocados-buy.md deleted file mode 100644 index 6b636ee267d..00000000000 --- a/.changeset/silver-avocados-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Update MultiNode with latest changes and bug fixes. Fixes an issue that caused nodes to go OutOfSync incorrectly, and also fixed context handling for sending transactions. #internal #bugfix diff --git a/.changeset/silver-books-grab.md b/.changeset/silver-books-grab.md deleted file mode 100644 index 2aa20e97f27..00000000000 --- a/.changeset/silver-books-grab.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#add #nops Add soneium config diff --git a/.changeset/six-camels-smell.md b/.changeset/six-camels-smell.md new file mode 100644 index 00000000000..a3667ed20e0 --- /dev/null +++ b/.changeset/six-camels-smell.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Bump to start the next version diff --git a/.changeset/six-coins-mix.md b/.changeset/six-coins-mix.md deleted file mode 100644 index 2877aa3012a..00000000000 --- a/.changeset/six-coins-mix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#bugfix fix: duplicate chain id in chain config dialog diff --git a/.changeset/soft-rivers-care.md b/.changeset/soft-rivers-care.md deleted file mode 100644 index 22eeea042ba..00000000000 --- a/.changeset/soft-rivers-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -interface change for plugin to support extra args codec, right now noop #added diff --git a/.changeset/sour-hairs-cross.md b/.changeset/sour-hairs-cross.md deleted file mode 100644 index fa12a38b5be..00000000000 --- a/.changeset/sour-hairs-cross.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#internal depreciate keystone deployment library diff --git a/.changeset/spotty-knives-smile.md b/.changeset/spotty-knives-smile.md deleted file mode 100644 index 8389b72414c..00000000000 --- a/.changeset/spotty-knives-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Increase GasLimit for Automation on ZKsync to 6M #nops diff --git a/.changeset/spotty-seals-give.md b/.changeset/spotty-seals-give.md deleted file mode 100644 index 1e3874a783f..00000000000 --- a/.changeset/spotty-seals-give.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Switching CCIP to observed ChainReader for HomeChainReader #internal diff --git a/.changeset/tall-falcons-yawn.md b/.changeset/tall-falcons-yawn.md deleted file mode 100644 index 98b90e5994b..00000000000 --- a/.changeset/tall-falcons-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -#added the ability to define a fallback.toml override config using CL_CHAIN_DEFAULTS env var diff --git a/.changeset/thick-vans-tickle.md b/.changeset/thick-vans-tickle.md deleted file mode 100644 index a719bf8905b..00000000000 --- a/.changeset/thick-vans-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Add support for flexible schemas #added diff --git a/.changeset/thin-cats-try.md b/.changeset/thin-cats-try.md deleted file mode 100644 index e7934fe279a..00000000000 --- a/.changeset/thin-cats-try.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Add support for Mercury LLO streams to feeds service. #added diff --git a/.changeset/thin-emus-wait.md b/.changeset/thin-emus-wait.md deleted file mode 100644 index 98b91952c27..00000000000 --- a/.changeset/thin-emus-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -fix solana client calls and update solana ref. #internal diff --git a/.changeset/tiny-kangaroos-switch.md b/.changeset/tiny-kangaroos-switch.md deleted file mode 100644 index 000f5b6bde5..00000000000 --- a/.changeset/tiny-kangaroos-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Added new fatal error cases for transactions to the Solana TXM. #added diff --git a/.changeset/tricky-clouds-move.md b/.changeset/tricky-clouds-move.md deleted file mode 100644 index 8cb50dbb048..00000000000 --- a/.changeset/tricky-clouds-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Updated Solana TXM to store prebroadcast transaction errors caught upfront by simulation. Refactored error parsing to more easily introduce new error cases. Optimized storing finalized and errored transaction to minimize memory usage. #updated diff --git a/.changeset/warm-panthers-stare.md b/.changeset/warm-panthers-stare.md deleted file mode 100644 index 319a7ad22b3..00000000000 --- a/.changeset/warm-panthers-stare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Add grpc support for LLO #added diff --git a/.changeset/wet-bags-clean.md b/.changeset/wet-bags-clean.md deleted file mode 100644 index 53da05426c9..00000000000 --- a/.changeset/wet-bags-clean.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Change ChainWriter naming to ContractWriter to consolidate Relayer chain interfaces #internal diff --git a/.changeset/wild-cats-think.md b/.changeset/wild-cats-think.md deleted file mode 100644 index f56f41b242c..00000000000 --- a/.changeset/wild-cats-think.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -Added the `EVM.Transactions.Enabled` config to enable or disable the transaction manager. #added diff --git a/.changeset/wild-planes-mix.md b/.changeset/wild-planes-mix.md deleted file mode 100644 index 1a08c2f9d4d..00000000000 --- a/.changeset/wild-planes-mix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Truncates workflow name before starting engine diff --git a/.changeset/wise-buttons-fry.md b/.changeset/wise-buttons-fry.md deleted file mode 100644 index aa3cb1dab79..00000000000 --- a/.changeset/wise-buttons-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": patch ---- - -Add TRON integration #added diff --git a/.changeset/yellow-brooms-leave.md b/.changeset/yellow-brooms-leave.md deleted file mode 100644 index 638751814bf..00000000000 --- a/.changeset/yellow-brooms-leave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"chainlink": minor ---- - -#updated feat:create tron chain config on operator ui diff --git a/CHANGELOG.md b/CHANGELOG.md index d5b6332c5a5..16647fb4b9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,170 @@ # Changelog Chainlink Core +## 2.20.0 - UNRELEASED + +### Minor Changes + +- [#15741](https://github.com/smartcontractkit/chainlink/pull/15741) [`37d30814fd`](https://github.com/smartcontractkit/chainlink/commit/37d30814fda19dfc61f7952a691b96036df2ed36) - #updated Gracefully fail if CL_DATABASE_URL is not set. + +- [#15699](https://github.com/smartcontractkit/chainlink/pull/15699) [`329e8f02fd`](https://github.com/smartcontractkit/chainlink/commit/329e8f02fdd4becd333878991a4463423082aaba) - #updated feat(job-distributor): support tron chain type on sync + +- [#15330](https://github.com/smartcontractkit/chainlink/pull/15330) [`35ef812d7f`](https://github.com/smartcontractkit/chainlink/commit/35ef812d7fc8ccaa31f362980b06b782ce2dcb29) - #removed Remove duplicated testing util for p2p_key only. + +- [#15416](https://github.com/smartcontractkit/chainlink/pull/15416) [`dcc6a36763`](https://github.com/smartcontractkit/chainlink/commit/dcc6a367633eedf0ad2f7b054f0892c53d6b4506) - #updated Remove custom ed25519 private to public key conversion. + +- [#15307](https://github.com/smartcontractkit/chainlink/pull/15307) [`a3c8092824`](https://github.com/smartcontractkit/chainlink/commit/a3c809282446174c8a13b78e83c3a76a3efca171) - #removed Remove unused ocr1 key files. + +- [#15537](https://github.com/smartcontractkit/chainlink/pull/15537) [`c1e92afb86`](https://github.com/smartcontractkit/chainlink/commit/c1e92afb86595ec1d4610974a1566417fa9ee316) - #internal Refactored ChainComponents tests to run in parallel + +- [#15996](https://github.com/smartcontractkit/chainlink/pull/15996) [`538b4eb636`](https://github.com/smartcontractkit/chainlink/commit/538b4eb636fc19e539e17d92c579ce96ec8829e0) - #added beholder metric to monitor TXMv2 transactions. + +- [#15888](https://github.com/smartcontractkit/chainlink/pull/15888) [`6e09ac75d5`](https://github.com/smartcontractkit/chainlink/commit/6e09ac75d556c8b05099f7dba78e1db79324ac3f) - add reorg detection for Solana TXM. #added + +- [#15776](https://github.com/smartcontractkit/chainlink/pull/15776) [`06a44452f9`](https://github.com/smartcontractkit/chainlink/commit/06a44452f9607ac6fb74a3ff05b59fa833c38c91) - Fix logic for mapping affected files in CI that affects golangci-lint execution + +- [#15935](https://github.com/smartcontractkit/chainlink/pull/15935) [`d44df0154f`](https://github.com/smartcontractkit/chainlink/commit/d44df0154fb0e0e29d9cd5517d22dedc778a5d3e) - #updated Bump chainlink-common version. + +- [#15269](https://github.com/smartcontractkit/chainlink/pull/15269) [`00777b83e1`](https://github.com/smartcontractkit/chainlink/commit/00777b83e1086c2541303926b5063794ec41dc7f) - Update deployment address book to support non-evm chains + +- [#15213](https://github.com/smartcontractkit/chainlink/pull/15213) [`1f44f3c40b`](https://github.com/smartcontractkit/chainlink/commit/1f44f3c40b4e49ebd58aea2e2ae60ec7e972776a) - Refactor chain ID logic in plugin to be chain agnostic #added + +- [#14326](https://github.com/smartcontractkit/chainlink/pull/14326) [`adf13dc1f1`](https://github.com/smartcontractkit/chainlink/commit/adf13dc1f11e2321a9b67a483c6f1e0594e77c85) - #internal Add unexposed shell cmd for updating a bridge + +- [#15323](https://github.com/smartcontractkit/chainlink/pull/15323) [`9eceab5b88`](https://github.com/smartcontractkit/chainlink/commit/9eceab5b88fce2ee23f440f25c0b20df3e1d4b1d) - #updated chainconfig: show chain type next to key bundle id in UI + +- [#15437](https://github.com/smartcontractkit/chainlink/pull/15437) [`b368079f5e`](https://github.com/smartcontractkit/chainlink/commit/b368079f5e6205df46b3335d6c2acbea359b2733) - Added TxExpirationRebroadcast feature and config for Solana TXM. #added + +- [#16005](https://github.com/smartcontractkit/chainlink/pull/16005) [`eea54da625`](https://github.com/smartcontractkit/chainlink/commit/eea54da625244de1ef14e56738e0a2337e298575) - #updated Explicitly use protoc installed in the makefile. + +- [#15565](https://github.com/smartcontractkit/chainlink/pull/15565) [`0fd3c7a828`](https://github.com/smartcontractkit/chainlink/commit/0fd3c7a828ac3701daef2656960fa2c10ba2aeb8) - #removed dead transmission tests + +- [#15944](https://github.com/smartcontractkit/chainlink/pull/15944) [`ed5cb0880a`](https://github.com/smartcontractkit/chainlink/commit/ed5cb0880a5c9cb1f31c4ecdadc05b1de0168f17) - interface change for plugin to support extra args codec, right now noop #added + +- [#15412](https://github.com/smartcontractkit/chainlink/pull/15412) [`fcc8d3c10c`](https://github.com/smartcontractkit/chainlink/commit/fcc8d3c10c8c8a757f113d9a9acb34997cb935b7) - Add support for Mercury LLO streams to feeds service. #added + +- [#15429](https://github.com/smartcontractkit/chainlink/pull/15429) [`030fd7c530`](https://github.com/smartcontractkit/chainlink/commit/030fd7c5309b43148a637fd762bf346467275bc6) - Change ChainWriter naming to ContractWriter to consolidate Relayer chain interfaces #internal + +- [#15714](https://github.com/smartcontractkit/chainlink/pull/15714) [`e706d72ab3`](https://github.com/smartcontractkit/chainlink/commit/e706d72ab3a6cf0e718555224ef671fc30b52dbe) - Added the `EVM.Transactions.Enabled` config to enable or disable the transaction manager. #added + +- [#15899](https://github.com/smartcontractkit/chainlink/pull/15899) [`796357b17c`](https://github.com/smartcontractkit/chainlink/commit/796357b17ca875ba80e157fc08b0da5db4ed1644) - #updated feat:create tron chain config on operator ui + +### Patch Changes + +- [#15357](https://github.com/smartcontractkit/chainlink/pull/15357) [`18cb44e891`](https://github.com/smartcontractkit/chainlink/commit/18cb44e891a00edff7486640ffc8e0c9275a04f8) - #updated use real contracts in ccipreader_tests where possible + +- [#15573](https://github.com/smartcontractkit/chainlink/pull/15573) [`eaeb2ebe7b`](https://github.com/smartcontractkit/chainlink/commit/eaeb2ebe7bfc53572655be322b793f0bf9556e1e) - #bugfix fix non-idempotent loopp registry.Register + +- [#15482](https://github.com/smartcontractkit/chainlink/pull/15482) [`35c2f05853`](https://github.com/smartcontractkit/chainlink/commit/35c2f05853ea1ba28be2c74941674289943b2fe6) - Potential bug introduced from chain selector refactor, not causing issue now since only EVM is used, but need to fix #bugfix + +- [#15293](https://github.com/smartcontractkit/chainlink/pull/15293) [`466586309a`](https://github.com/smartcontractkit/chainlink/commit/466586309a8cbbfc1c793ff1021b7fcd3522dd3e) - allow different decimals on different chains for token pools + +- [#15271](https://github.com/smartcontractkit/chainlink/pull/15271) [`1231f1417e`](https://github.com/smartcontractkit/chainlink/commit/1231f1417e7fddeca190c2ab037e84c4858181df) - Updated the Solana TXM compute unit limit estimation feature to use the max 1.4M compute unit limit for simulation and enable SigVerify #updated + +- [#15321](https://github.com/smartcontractkit/chainlink/pull/15321) [`29eb7554a6`](https://github.com/smartcontractkit/chainlink/commit/29eb7554a62d46f17b7d64674ad01910a03023d1) - Removing ccip-tests/\* dependencies and moving ccip tests under a directory in smoke + +- [#15539](https://github.com/smartcontractkit/chainlink/pull/15539) [`49b77048d1`](https://github.com/smartcontractkit/chainlink/commit/49b77048d1b5480a07b9f77b32b005379c679c44) - Adding OCR3 promwrapper to LLO #internal + +- [#15858](https://github.com/smartcontractkit/chainlink/pull/15858) [`7debe85cc4`](https://github.com/smartcontractkit/chainlink/commit/7debe85cc458774c0d94c8d2221a9cb17679fbff) - #added Sei config and error mapping + +- [#15852](https://github.com/smartcontractkit/chainlink/pull/15852) [`fcefd62068`](https://github.com/smartcontractkit/chainlink/commit/fcefd62068d6be4fea1820d1a9edef4e16fbfa3b) - #internal minor rename of various gethwrappers + +- [#15791](https://github.com/smartcontractkit/chainlink/pull/15791) [`2450fff71d`](https://github.com/smartcontractkit/chainlink/commit/2450fff71db772d7e771babb5cbe1a55f5a51f84) - Extract EVM MultiNode to chainlink-framework. #internal + +- [#15831](https://github.com/smartcontractkit/chainlink/pull/15831) [`8270318279`](https://github.com/smartcontractkit/chainlink/commit/8270318279ab992328288973f2b831aa9440f6b1) - #internal adding solana devnet to ccip deployment + +- [#15921](https://github.com/smartcontractkit/chainlink/pull/15921) [`415343f304`](https://github.com/smartcontractkit/chainlink/commit/415343f304b574d4f024a82e0fad266060c34cf5) - validates response from gateway in workflow/fetcher + +- [#15544](https://github.com/smartcontractkit/chainlink/pull/15544) [`036cb20d43`](https://github.com/smartcontractkit/chainlink/commit/036cb20d43b8f2d3cdb4de79d11f97ff63831025) - Reporting number of OCR3 instances running using promwrapper #internal + +- [#15950](https://github.com/smartcontractkit/chainlink/pull/15950) [`f9dd7e13bc`](https://github.com/smartcontractkit/chainlink/commit/f9dd7e13bc952e1f006f7e5c663b0953aa565cce) - Prevents a panic in test helper for confirming transaction + and adds encrypted public key to a peer before calling addNodes + on CapabilitiesRegistry + +- [#15121](https://github.com/smartcontractkit/chainlink/pull/15121) [`5d22ba8dd2`](https://github.com/smartcontractkit/chainlink/commit/5d22ba8dd2269b11e024e3bc93fc90225034abf7) - #added Adding 5 chains (B^2, BoB, Berachain, Unichain, Worldchain configs) + +- [#15735](https://github.com/smartcontractkit/chainlink/pull/15735) [`7743429082`](https://github.com/smartcontractkit/chainlink/commit/7743429082e6c404d6db1877242b747ddd5f6e40) - Reduce PriceMin on Avalanche to 1 gwei #nops + +- [#15846](https://github.com/smartcontractkit/chainlink/pull/15846) [`6aa365d600`](https://github.com/smartcontractkit/chainlink/commit/6aa365d600b0f7b9473344942adb9f04f9fb4106) - Add panic recovery to wsrpc mercury client + + - Should help to make nodes running wsrpc v0.8.2 more stable #bugfix + +- [#15913](https://github.com/smartcontractkit/chainlink/pull/15913) [`d0a7df39f0`](https://github.com/smartcontractkit/chainlink/commit/d0a7df39f0391b15d67ba5f4ad2268d40d0b3359) - #bugfix Add chaintype.ChainZircuit to chaintypes with rollup support in L1 oracle to prevent a nil L1 oracle being used for Zircuit's gas estimator + +- [#15690](https://github.com/smartcontractkit/chainlink/pull/15690) [`ed6f486d59`](https://github.com/smartcontractkit/chainlink/commit/ed6f486d59c2cbdfa02c6fbfc3a42fb6d5f805a2) - #added stream job delete capability + +- [#15605](https://github.com/smartcontractkit/chainlink/pull/15605) [`8c65527c82`](https://github.com/smartcontractkit/chainlink/commit/8c65527c82a20c74b2a4707221ef496802b21804) - Changed RMNRemote and RMNHome parameter f to fObserve and fSign #updated + +- [#15829](https://github.com/smartcontractkit/chainlink/pull/15829) [`6e65deecae`](https://github.com/smartcontractkit/chainlink/commit/6e65deecae053ee1e885da7ce6d1d308364ced1d) - #internal change gethwrapper to allow for foundry based gethwrapper generation + +- [#15521](https://github.com/smartcontractkit/chainlink/pull/15521) [`f6f2457d93`](https://github.com/smartcontractkit/chainlink/commit/f6f2457d9367c543bef20491a26785266849c154) - Prometheus observability layer added to OCR3 Reporting Plugins #internal + +- [#15624](https://github.com/smartcontractkit/chainlink/pull/15624) [`8f6c3b461b`](https://github.com/smartcontractkit/chainlink/commit/8f6c3b461b05b4686b98d31a3c85df078328d526) - #added Lens Sepolia config + +- [#15488](https://github.com/smartcontractkit/chainlink/pull/15488) [`52f364a6cd`](https://github.com/smartcontractkit/chainlink/commit/52f364a6cd842fe63c4cab6182f4c9fbbf7d134e) - Add error handling for Arbitrum RPC server timeouts. #added + +- [#15616](https://github.com/smartcontractkit/chainlink/pull/15616) [`c57f910327`](https://github.com/smartcontractkit/chainlink/commit/c57f910327ad2a0cb104a156b289f75b5bb7d972) - Updated TXM abandon transaction functionality to drop related attempts. #updated + +- [#15339](https://github.com/smartcontractkit/chainlink/pull/15339) [`0cabe54f85`](https://github.com/smartcontractkit/chainlink/commit/0cabe54f8535a466a5404bac67396071ec058d94) - fix reported evm node states + +- [#15470](https://github.com/smartcontractkit/chainlink/pull/15470) [`54938d4ad2`](https://github.com/smartcontractkit/chainlink/commit/54938d4ad2b430d4941eaae711abe5e1e6a7686a) - #internal refactor: inject ocr secrets via env instead of config + +- [#15362](https://github.com/smartcontractkit/chainlink/pull/15362) [`6ea458859f`](https://github.com/smartcontractkit/chainlink/commit/6ea458859f19835d671455c5ce48a5d91cc9d6aa) - Add two new metrics for monitoring LLO transmitter health #added + + `llo_mercurytransmitter_concurrent_transmit_gauge` + Gauge that measures the number of transmit threads currently waiting on a remote transmit call. You may wish to alert if this exceeds some number for a given period of time, or if it ever reaches its max. + + `llo_mercurytransmitter_concurrent_delete_gauge` + Gauge that measures the number of delete threads currently waiting on a delete call to the DB. You may wish to alert if this exceeds some number for a given period of time, or if it ever reaches its max. + +- [#15425](https://github.com/smartcontractkit/chainlink/pull/15425) [`f094f6c550`](https://github.com/smartcontractkit/chainlink/commit/f094f6c550df43b761d71fdf10cc70bf71a7a318) - Fix TransactionSender go routine leak. #bugfix + +- [#15897](https://github.com/smartcontractkit/chainlink/pull/15897) [`47a0c4227c`](https://github.com/smartcontractkit/chainlink/commit/47a0c4227c1ccdd93a7b0a6365e7e1c78c74b6d7) - DEVSVCS-958: fix automation v2.3 batching bug #bugfix + +- [#15543](https://github.com/smartcontractkit/chainlink/pull/15543) [`7b6e20f1b4`](https://github.com/smartcontractkit/chainlink/commit/7b6e20f1b40506467349eb0203178aa2c51f5d41) - #internal refactor update nodes changeset to support mcms + +- [#15985](https://github.com/smartcontractkit/chainlink/pull/15985) [`87e0fdfaac`](https://github.com/smartcontractkit/chainlink/commit/87e0fdfaac5cc80b571c5ed4d5837576279daa27) - #added core configs + +- [#15169](https://github.com/smartcontractkit/chainlink/pull/15169) [`1341a3a39b`](https://github.com/smartcontractkit/chainlink/commit/1341a3a39be8987bae7318f7f3dba0e9b0f31c49) - Add config var Mercury.Transmitter.TransmitConcurrency #added + +- [#15785](https://github.com/smartcontractkit/chainlink/pull/15785) [`cb36e64cb1`](https://github.com/smartcontractkit/chainlink/commit/cb36e64cb14e6c67967d667b2b37f00bbba11ab0) - #internal add versioned geth wrappers for keystone prod contracts + +- [#15457](https://github.com/smartcontractkit/chainlink/pull/15457) [`f6dfb4e87b`](https://github.com/smartcontractkit/chainlink/commit/f6dfb4e87b8cf58ccb2646737f354f2453d07940) - Fixes a race condition with the Finalizer when clearing txs #bugfix + +- [#15603](https://github.com/smartcontractkit/chainlink/pull/15603) [`c7759e15e2`](https://github.com/smartcontractkit/chainlink/commit/c7759e15e2b15bdeacf00ddbd433a4b420072cf3) - Support multiple streamIDs in stream specs #added + +- [#15932](https://github.com/smartcontractkit/chainlink/pull/15932) [`186fda8dc3`](https://github.com/smartcontractkit/chainlink/commit/186fda8dc3c4bae8abc436efc0e64d44b86b7628) - #bugfix Fix missing Tron handler + +- [#15169](https://github.com/smartcontractkit/chainlink/pull/15169) [`1341a3a39b`](https://github.com/smartcontractkit/chainlink/commit/1341a3a39be8987bae7318f7f3dba0e9b0f31c49) - Logging improvements for LLO + #internal + +- [#15058](https://github.com/smartcontractkit/chainlink/pull/15058) [`d4d1456cc7`](https://github.com/smartcontractkit/chainlink/commit/d4d1456cc7d4b0828c1b5e270857636762680e04) - Update MultiNode with latest changes and bug fixes. Fixes an issue that caused nodes to go OutOfSync incorrectly, and also fixed context handling for sending transactions. #internal #bugfix + +- [#15883](https://github.com/smartcontractkit/chainlink/pull/15883) [`182575a823`](https://github.com/smartcontractkit/chainlink/commit/182575a823d8e011f4a03a8a69d5498ef5346019) - #add #nops Add soneium config + +- [#15585](https://github.com/smartcontractkit/chainlink/pull/15585) [`99b666fbcb`](https://github.com/smartcontractkit/chainlink/commit/99b666fbcbccb926e6dbac11896bf7e7ee5c25ea) - #bugfix fix: duplicate chain id in chain config dialog + +- [#15759](https://github.com/smartcontractkit/chainlink/pull/15759) [`0b8172dfcc`](https://github.com/smartcontractkit/chainlink/commit/0b8172dfcc9bc5ca3c166139286b9675239250c8) - #internal depreciate keystone deployment library + +- [#15474](https://github.com/smartcontractkit/chainlink/pull/15474) [`b0ea0ca066`](https://github.com/smartcontractkit/chainlink/commit/b0ea0ca0665ef5ebd2136fe4392c8b3ee7f49d12) - Increase GasLimit for Automation on ZKsync to 6M #nops + +- [#15628](https://github.com/smartcontractkit/chainlink/pull/15628) [`6101be751e`](https://github.com/smartcontractkit/chainlink/commit/6101be751e8c1088e53bcf7e1c2481f4215d420f) - Switching CCIP to observed ChainReader for HomeChainReader #internal + +- [#15617](https://github.com/smartcontractkit/chainlink/pull/15617) [`5b503a3c02`](https://github.com/smartcontractkit/chainlink/commit/5b503a3c02801809533012cd73b5f7c492f73ac8) - #added the ability to define a fallback.toml override config using CL_CHAIN_DEFAULTS env var + +- [#15493](https://github.com/smartcontractkit/chainlink/pull/15493) [`16eeb3b5de`](https://github.com/smartcontractkit/chainlink/commit/16eeb3b5de6526f4a53bad2d38be581506cdbfd1) - Add support for flexible schemas #added + +- [#16010](https://github.com/smartcontractkit/chainlink/pull/16010) [`5dd3d80200`](https://github.com/smartcontractkit/chainlink/commit/5dd3d80200a7f5528998cca1ac038d33bab70593) - fix solana client calls and update solana ref. #internal + +- [#15604](https://github.com/smartcontractkit/chainlink/pull/15604) [`5f3aa78bce`](https://github.com/smartcontractkit/chainlink/commit/5f3aa78bce9f13f5bee26b8a53cb5a1f14ea9102) - Added new fatal error cases for transactions to the Solana TXM. #added + +- [#15369](https://github.com/smartcontractkit/chainlink/pull/15369) [`cb194d72a4`](https://github.com/smartcontractkit/chainlink/commit/cb194d72a4ea88831eaf7e6505c582f6dc312d27) - Updated Solana TXM to store prebroadcast transaction errors caught upfront by simulation. Refactored error parsing to more easily introduce new error cases. Optimized storing finalized and errored transaction to minimize memory usage. #updated + +- [#15924](https://github.com/smartcontractkit/chainlink/pull/15924) [`50c7453965`](https://github.com/smartcontractkit/chainlink/commit/50c745396596a40e230ffcb4681788440b6df908) - Add grpc support for LLO #added + +- [#15896](https://github.com/smartcontractkit/chainlink/pull/15896) [`9fab5114b5`](https://github.com/smartcontractkit/chainlink/commit/9fab5114b59c0c5dbb29b7c2af5ca5f035ea13d0) - Truncates workflow name before starting engine + +- [#14783](https://github.com/smartcontractkit/chainlink/pull/14783) [`0199523f90`](https://github.com/smartcontractkit/chainlink/commit/0199523f9042d58c87ea2909e10e7468aa5b36c1) - Add TRON integration #added + ## 2.19.0 - 2024-12-12 ### Minor Changes diff --git a/package.json b/package.json index 8a0b5a3ed5d..465595a3c9d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chainlink", - "version": "2.19.0", + "version": "2.20.0", "description": "node of the decentralized oracle network, bridging on and off-chain computation", "main": "index.js", "scripts": { From 16a7985836d2055aca62d4cd331f2d374792d0d1 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Thu, 30 Jan 2025 17:09:07 +0100 Subject: [PATCH 11/43] Dedup weth and move to vendor (#16141) * move ccip weth to vendor * automation weth * gen in shared * swap out usage * changeset * [Bot] Update changeset file with jira issues * fix import --------- Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> --- contracts/.changeset/gold-items-dance.md | 10 + .../native_solc_compile_all_automation | 1 - .../scripts/native_solc_compile_all_ccip | 1 - .../scripts/native_solc_compile_all_shared | 1 + contracts/src/v0.8/automation/test/WETH9.sol | 93 -- .../v0.8/automation/test/v2_3/BaseTest.t.sol | 15 +- .../test/v2_3_zksync/BaseTest.t.sol | 15 +- contracts/src/v0.8/ccip/test/BaseTest.t.sol | 2 +- .../EtherSenderReceiverTestSetup.t.sol | 2 +- .../test/LiquidityManagerBaseTest.t.sol | 3 +- .../OptimismL1BridgeAdapter.t.sol | 2 +- .../test => vendor/canonical-weth}/WETH9.sol | 2 +- ...rapper-dependency-versions-do-not-edit.txt | 1 - core/gethwrappers/ccip/go_generate.go | 1 - .../generated/weth9_wrapper/weth9_wrapper.go | 1010 ----------------- ...rapper-dependency-versions-do-not-edit.txt | 1 - core/gethwrappers/go_generate.go | 1 - .../{ccip => shared}/generated/weth9/weth9.go | 2 +- ...rapper-dependency-versions-do-not-edit.txt | 1 + core/gethwrappers/shared/go_generate.go | 1 + .../ccip/testhelpers/ccip_contracts.go | 2 +- .../testhelpers_1_4_0/ccip_contracts_1_4_0.go | 2 +- deployment/ccip/changeset/cs_prerequisites.go | 2 +- deployment/ccip/changeset/state.go | 18 +- deployment/ccip/changeset/token_info.go | 2 +- .../ccip-tests/contracts/contract_deployer.go | 2 +- .../contracts/ethereum_contracts.go | 16 +- .../smoke/ccip/ccip_fees_test.go | 4 +- 28 files changed, 58 insertions(+), 1155 deletions(-) create mode 100644 contracts/.changeset/gold-items-dance.md delete mode 100644 contracts/src/v0.8/automation/test/WETH9.sol rename contracts/src/v0.8/{ccip/test => vendor/canonical-weth}/WETH9.sol (99%) delete mode 100644 core/gethwrappers/generated/weth9_wrapper/weth9_wrapper.go rename core/gethwrappers/{ccip => shared}/generated/weth9/weth9.go (83%) diff --git a/contracts/.changeset/gold-items-dance.md b/contracts/.changeset/gold-items-dance.md new file mode 100644 index 00000000000..0da36b92c8f --- /dev/null +++ b/contracts/.changeset/gold-items-dance.md @@ -0,0 +1,10 @@ +--- +'@chainlink/contracts': patch +--- + +#internal move multiple weth9 implementations to vendor + + +PR issue: CCIP-5081 + +Solidity Review issue: CCIP-3966 \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index eb4b39201ba..32a7b2d60eb 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -108,4 +108,3 @@ compileContract automation/v2_3/AutomationUtils2_3.sol compileContract automation/interfaces/v2_3/IAutomationRegistryMaster2_3.sol compileContract automation/testhelpers/MockETHUSDAggregator.sol -compileContract automation/test/WETH9.sol diff --git a/contracts/scripts/native_solc_compile_all_ccip b/contracts/scripts/native_solc_compile_all_ccip index 91ce5ef8729..416e079ac7f 100755 --- a/contracts/scripts/native_solc_compile_all_ccip +++ b/contracts/scripts/native_solc_compile_all_ccip @@ -86,7 +86,6 @@ compileContract test/helpers/receivers/LogMessageDataReceiver compileContract test/helpers/MultiOCR3Helper compileContract test/mocks/MockE2EUSDCTokenMessenger compileContract test/mocks/MockE2EUSDCTransmitter -compileContract test/WETH9 compileContract test/helpers/CCIPReaderTester # Offchain test encoding utils compileContract test/helpers/EncodingUtils diff --git a/contracts/scripts/native_solc_compile_all_shared b/contracts/scripts/native_solc_compile_all_shared index 1b251db7d9b..97510629c0a 100755 --- a/contracts/scripts/native_solc_compile_all_shared +++ b/contracts/scripts/native_solc_compile_all_shared @@ -47,3 +47,4 @@ compileContract mocks/WERC20Mock compileContract openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20 vendor compileContract multicall/ebd8b64/src/Multicall3 vendor +compileContract canonical-weth/WETH9 vendor diff --git a/contracts/src/v0.8/automation/test/WETH9.sol b/contracts/src/v0.8/automation/test/WETH9.sol deleted file mode 100644 index 1225e6e39a8..00000000000 --- a/contracts/src/v0.8/automation/test/WETH9.sol +++ /dev/null @@ -1,93 +0,0 @@ -// Submitted for verification at Etherscan.io on 2017-12-12 - -// Copyright (C) 2015, 2016, 2017 Dapphub - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -pragma solidity 0.8.19; - -contract WETH9 { - string public name = "Wrapped Ether"; - string public symbol = "WETH"; - uint8 public decimals = 18; - - event Approval(address indexed src, address indexed guy, uint256 wad); - event Transfer(address indexed src, address indexed dst, uint256 wad); - event Deposit(address indexed dst, uint256 wad); - event Withdrawal(address indexed src, uint256 wad); - - error InsufficientBalance(); - - mapping(address => uint256) public balanceOf; - mapping(address => mapping(address => uint256)) public allowance; - - receive() external payable { - _deposit(); - } - - function _deposit() internal { - balanceOf[msg.sender] += msg.value; - emit Deposit(msg.sender, msg.value); - } - - function deposit() external payable { - _deposit(); - } - - function mint(address account, uint256 amount) public { - balanceOf[account] += amount; - } - - function withdraw(uint256 wad) external { - if (balanceOf[msg.sender] < wad) { - revert InsufficientBalance(); - } - balanceOf[msg.sender] -= wad; - payable(msg.sender).call{value: wad}(""); - emit Withdrawal(msg.sender, wad); - } - - function totalSupply() public view returns (uint256) { - return address(this).balance; - } - - function approve(address guy, uint256 wad) public returns (bool) { - allowance[msg.sender][guy] = wad; - emit Approval(msg.sender, guy, wad); - return true; - } - - function transfer(address dst, uint256 wad) public returns (bool) { - return transferFrom(msg.sender, dst, wad); - } - - function transferFrom(address src, address dst, uint256 wad) public returns (bool) { - if (balanceOf[src] < wad) { - revert InsufficientBalance(); - } - - if (src != msg.sender && allowance[src][msg.sender] != type(uint128).max) { - if (allowance[src][msg.sender] < wad) { - revert InsufficientBalance(); - } - allowance[src][msg.sender] -= wad; - } - - balanceOf[src] -= wad; - balanceOf[dst] += wad; - - emit Transfer(src, dst, wad); - - return true; - } -} 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 44bb0f0ae60..8e3f9760463 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 @@ -4,7 +4,6 @@ pragma solidity 0.8.19; import "forge-std/Test.sol"; import {LinkToken} from "../../../shared/token/ERC677/LinkToken.sol"; -import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {ERC20Mock6Decimals} from "../../mocks/ERC20Mock6Decimals.sol"; import {MockV3Aggregator} from "../../../shared/mocks/MockV3Aggregator.sol"; import {AutomationForwarderLogic} from "../../AutomationForwarderLogic.sol"; @@ -17,10 +16,12 @@ import {AutomationRegistryLogicC2_3} from "../../v2_3/AutomationRegistryLogicC2_ import {IAutomationRegistryMaster2_3 as Registry, AutomationRegistryBase2_3} from "../../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; import {AutomationRegistrar2_3} from "../../v2_3/AutomationRegistrar2_3.sol"; import {ChainModuleBase} from "../../chains/ChainModuleBase.sol"; -import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {MockUpkeep} from "../../mocks/MockUpkeep.sol"; import {IWrappedNative} from "../../interfaces/v2_3/IWrappedNative.sol"; -import {WETH9} from "../WETH9.sol"; + +import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {WETH9} from "../../../vendor/canonical-weth/WETH9.sol"; /** * @title BaseTest provides basic test setup procedures and dependencies for use by other @@ -137,10 +138,10 @@ contract BaseTest is Test { usdToken6.mint(FINANCE_ADMIN, 1000e6); usdToken6.mint(STRANGER, 1000e6); - weth.mint(OWNER, 1000e18); - weth.mint(UPKEEP_ADMIN, 1000e18); - weth.mint(FINANCE_ADMIN, 1000e18); - weth.mint(STRANGER, 1000e18); + deal(address(weth), OWNER, 100 ether); + deal(address(weth), UPKEEP_ADMIN, 100 ether); + deal(address(weth), FINANCE_ADMIN, 100 ether); + deal(address(weth), STRANGER, 100 ether); vm.stopPrank(); } 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 f33360aa9f6..0b534ef3575 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 @@ -4,7 +4,6 @@ pragma solidity 0.8.19; import "forge-std/Test.sol"; import {LinkToken} from "../../../shared/token/ERC677/LinkToken.sol"; -import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; import {ERC20Mock6Decimals} from "../../mocks/ERC20Mock6Decimals.sol"; import {MockV3Aggregator} from "../../../shared/mocks/MockV3Aggregator.sol"; import {AutomationForwarderLogic} from "../../AutomationForwarderLogic.sol"; @@ -17,13 +16,15 @@ import {ZKSyncAutomationRegistryBase2_3 as ZKSyncAutoBase} from "../../v2_3_zksy import {IAutomationRegistryMaster2_3 as Registry, AutomationRegistryBase2_3} from "../../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; import {AutomationRegistrar2_3} from "../../v2_3/AutomationRegistrar2_3.sol"; import {ChainModuleBase} from "../../chains/ChainModuleBase.sol"; -import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {MockUpkeep} from "../../mocks/MockUpkeep.sol"; import {IWrappedNative} from "../../interfaces/v2_3/IWrappedNative.sol"; -import {WETH9} from "../WETH9.sol"; import {MockGasBoundCaller} from "../../mocks/MockGasBoundCaller.sol"; import {MockZKSyncSystemContext} from "../../mocks/MockZKSyncSystemContext.sol"; +import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; +import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {WETH9} from "../../../vendor/canonical-weth/WETH9.sol"; + /** * @title BaseTest provides basic test setup procedures and dependencies for use by other * unit tests @@ -149,10 +150,10 @@ contract BaseTest is Test { usdToken6.mint(FINANCE_ADMIN, 1000e6); usdToken6.mint(STRANGER, 1000e6); - weth.mint(OWNER, 1000e18); - weth.mint(UPKEEP_ADMIN, 1000e18); - weth.mint(FINANCE_ADMIN, 1000e18); - weth.mint(STRANGER, 1000e18); + deal(address(weth), OWNER, 100 ether); + deal(address(weth), UPKEEP_ADMIN, 100 ether); + deal(address(weth), FINANCE_ADMIN, 100 ether); + deal(address(weth), STRANGER, 100 ether); vm.stopPrank(); } diff --git a/contracts/src/v0.8/ccip/test/BaseTest.t.sol b/contracts/src/v0.8/ccip/test/BaseTest.t.sol index 1d30a8f589f..776a1d452b9 100644 --- a/contracts/src/v0.8/ccip/test/BaseTest.t.sol +++ b/contracts/src/v0.8/ccip/test/BaseTest.t.sol @@ -8,8 +8,8 @@ import {IRMNRemote} from "../interfaces/IRMNRemote.sol"; import {Router} from "../Router.sol"; import {Internal} from "../libraries/Internal.sol"; import {RateLimiter} from "../libraries/RateLimiter.sol"; -import {WETH9} from "./WETH9.sol"; +import {WETH9} from "../../vendor/canonical-weth/WETH9.sol"; import {Test} from "forge-std/Test.sol"; contract BaseTest is Test { diff --git a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTestSetup.t.sol b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTestSetup.t.sol index b989a11b3ef..2cdf1526923 100644 --- a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTestSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTestSetup.t.sol @@ -5,9 +5,9 @@ import {Test} from "forge-std/Test.sol"; import {ICCIPRouter} from "../../../applications/EtherSenderReceiver.sol"; -import {WETH9} from "../../WETH9.sol"; import {EtherSenderReceiverHelper} from "../../helpers/EtherSenderReceiverHelper.sol"; +import {WETH9} from "../../../../vendor/canonical-weth/WETH9.sol"; import {ERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol"; contract EtherSenderReceiverTestSetup is Test { diff --git a/contracts/src/v0.8/liquiditymanager/test/LiquidityManagerBaseTest.t.sol b/contracts/src/v0.8/liquiditymanager/test/LiquidityManagerBaseTest.t.sol index 5a7dda0607f..08bc1fa1efc 100644 --- a/contracts/src/v0.8/liquiditymanager/test/LiquidityManagerBaseTest.t.sol +++ b/contracts/src/v0.8/liquiditymanager/test/LiquidityManagerBaseTest.t.sol @@ -3,10 +3,9 @@ pragma solidity ^0.8.24; import {Test} from "forge-std/Test.sol"; -import {WETH9} from "../../ccip/test/WETH9.sol"; - import {ERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {WETH9} from "../../vendor/canonical-weth/WETH9.sol"; contract LiquidityManagerBaseTest is Test { IERC20 internal s_l1Token; diff --git a/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/OptimismL1BridgeAdapter.t.sol b/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/OptimismL1BridgeAdapter.t.sol index cface1d5067..3a49dbd14c7 100644 --- a/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/OptimismL1BridgeAdapter.t.sol +++ b/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/OptimismL1BridgeAdapter.t.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.24; import "forge-std/Test.sol"; import {IWrappedNative} from "../../../ccip/interfaces/IWrappedNative.sol"; -import {WETH9} from "../../../ccip/test/WETH9.sol"; import {OptimismL1BridgeAdapter} from "../../bridge-adapters/OptimismL1BridgeAdapter.sol"; import {Types} from "../../interfaces/optimism/Types.sol"; import {IOptimismPortal} from "../../interfaces/optimism/IOptimismPortal.sol"; @@ -12,6 +11,7 @@ import {IOptimismPortal} from "../../interfaces/optimism/IOptimismPortal.sol"; import {IL1StandardBridge} from "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol"; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {WETH9} from "../../../vendor/canonical-weth/WETH9.sol"; contract OptimismL1BridgeAdapterSetup is Test { // addresses below are fake diff --git a/contracts/src/v0.8/ccip/test/WETH9.sol b/contracts/src/v0.8/vendor/canonical-weth/WETH9.sol similarity index 99% rename from contracts/src/v0.8/ccip/test/WETH9.sol rename to contracts/src/v0.8/vendor/canonical-weth/WETH9.sol index 0ac79d413dd..51aec423896 100644 --- a/contracts/src/v0.8/ccip/test/WETH9.sol +++ b/contracts/src/v0.8/vendor/canonical-weth/WETH9.sol @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -pragma solidity ^0.8.24; +pragma solidity ^0.8.0; // solhint-disable contract WETH9 { diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt index fe79ca47e45..3bcfca3d97e 100644 --- a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -31,4 +31,3 @@ token_admin_registry: ../../../contracts/solc/ccip/TokenAdminRegistry/TokenAdmin token_pool: ../../../contracts/solc/ccip/TokenPool/TokenPool.sol/TokenPool.abi.json ../../../contracts/solc/ccip/TokenPool/TokenPool.sol/TokenPool.bin 6c00ce7b2082f40d5f9b4808eb692a90e81c312b4f5d70d62e4b1ef69a164a9f usdc_reader_tester: ../../../contracts/solc/ccip/USDCReaderTester/USDCReaderTester.sol/USDCReaderTester.abi.json ../../../contracts/solc/ccip/USDCReaderTester/USDCReaderTester.sol/USDCReaderTester.bin 7622b1e42bc9c3933c51607d765d8463796c615155596929e554a58ed68b263d usdc_token_pool: ../../../contracts/solc/ccip/USDCTokenPool/USDCTokenPool.sol/USDCTokenPool.abi.json ../../../contracts/solc/ccip/USDCTokenPool/USDCTokenPool.sol/USDCTokenPool.bin 8a44f8d2d193fc1332e5e80a5e05172dc15680e0921d7cc945ea321746f764fc -weth9: ../../../contracts/solc/ccip/WETH9/WETH9.sol/WETH9.abi.json ../../../contracts/solc/ccip/WETH9/WETH9.sol/WETH9.bin 89ee9892414b4d9abfb18046504aa7771c88c52a0831479ca4152f120e647d49 diff --git a/core/gethwrappers/ccip/go_generate.go b/core/gethwrappers/ccip/go_generate.go index 7061cca9a33..4e4822d9a2e 100644 --- a/core/gethwrappers/ccip/go_generate.go +++ b/core/gethwrappers/ccip/go_generate.go @@ -32,7 +32,6 @@ package ccip //go:generate go run ../generation/wrap.go ccip USDCReaderTester usdc_reader_tester //go:generate go run ../generation/wrap.go ccip ReportCodec report_codec //go:generate go run ../generation/wrap.go ccip EtherSenderReceiver ether_sender_receiver -//go:generate go run ../generation/wrap.go ccip WETH9 weth9 //go:generate go run ../generation/wrap.go ccip MockE2EUSDCTokenMessenger mock_usdc_token_messenger //go:generate go run ../generation/wrap.go ccip MockE2EUSDCTransmitter mock_usdc_token_transmitter //go:generate go run ../generation/wrap.go ccip CCIPReaderTester ccip_reader_tester diff --git a/core/gethwrappers/generated/weth9_wrapper/weth9_wrapper.go b/core/gethwrappers/generated/weth9_wrapper/weth9_wrapper.go deleted file mode 100644 index 87849c786f4..00000000000 --- a/core/gethwrappers/generated/weth9_wrapper/weth9_wrapper.go +++ /dev/null @@ -1,1010 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package weth9_wrapper - -import ( - "errors" - "fmt" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" -) - -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -var WETH9MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guy\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x60c0604052600d60809081526c2bb930b83832b21022ba3432b960991b60a05260009061002c9082610114565b506040805180820190915260048152630ae8aa8960e31b60208201526001906100559082610114565b506002805460ff1916601217905534801561006f57600080fd5b506101d3565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061009f57607f821691505b6020821081036100bf57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561010f57600081815260208120601f850160051c810160208610156100ec5750805b601f850160051c820191505b8181101561010b578281556001016100f8565b5050505b505050565b81516001600160401b0381111561012d5761012d610075565b6101418161013b845461008b565b846100c5565b602080601f831160018114610176576000841561015e5750858301515b600019600386901b1c1916600185901b17855561010b565b600085815260208120601f198616915b828110156101a557888601518255948401946001909101908401610186565b50858210156101c35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6109b680620001e36000396000f3fe6080604052600436106100cb5760003560e01c806340c10f1911610074578063a9059cbb1161004e578063a9059cbb14610225578063d0e30db014610245578063dd62ed3e1461024d57600080fd5b806340c10f19146101c357806370a08231146101e357806395d89b411461021057600080fd5b806323b872dd116100a557806323b872dd146101575780632e1a7d4d14610177578063313ce5671461019757600080fd5b806306fdde03146100df578063095ea7b31461010a57806318160ddd1461013a57600080fd5b366100da576100d8610285565b005b600080fd5b3480156100eb57600080fd5b506100f46102e0565b604051610101919061079f565b60405180910390f35b34801561011657600080fd5b5061012a610125366004610834565b61036e565b6040519015158152602001610101565b34801561014657600080fd5b50475b604051908152602001610101565b34801561016357600080fd5b5061012a61017236600461085e565b6103e8565b34801561018357600080fd5b506100d861019236600461089a565b610649565b3480156101a357600080fd5b506002546101b19060ff1681565b60405160ff9091168152602001610101565b3480156101cf57600080fd5b506100d86101de366004610834565b610736565b3480156101ef57600080fd5b506101496101fe3660046108b3565b60036020526000908152604090205481565b34801561021c57600080fd5b506100f4610774565b34801561023157600080fd5b5061012a610240366004610834565b610781565b6100d8610795565b34801561025957600080fd5b506101496102683660046108ce565b600460209081526000928352604080842090915290825290205481565b33600090815260036020526040812080543492906102a4908490610930565b909155505060405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a2565b600080546102ed90610943565b80601f016020809104026020016040519081016040528092919081815260200182805461031990610943565b80156103665780601f1061033b57610100808354040283529160200191610366565b820191906000526020600020905b81548152906001019060200180831161034957829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103d69086815260200190565b60405180910390a35060015b92915050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054821115610447576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff841633148015906104ad575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020546fffffffffffffffffffffffffffffffff14155b156105625773ffffffffffffffffffffffffffffffffffffffff8416600090815260046020908152604080832033845290915290205482111561051c576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091528120805484929061055c908490610996565b90915550505b73ffffffffffffffffffffffffffffffffffffffff841660009081526003602052604081208054849290610597908490610996565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812080548492906105d1908490610930565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161063791815260200190565b60405180910390a35060019392505050565b33600090815260036020526040902054811115610692576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260036020526040812080548392906106b1908490610996565b909155505060405133908290600081818185875af1925050503d80600081146106f6576040519150601f19603f3d011682016040523d82523d6000602084013e6106fb565b606091505b50506040518281523391507f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b659060200160405180910390a250565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805483929061076b908490610930565b90915550505050565b600180546102ed90610943565b600061078e3384846103e8565b9392505050565b61079d610285565b565b600060208083528351808285015260005b818110156107cc578581018301518582016040015282016107b0565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461082f57600080fd5b919050565b6000806040838503121561084757600080fd5b6108508361080b565b946020939093013593505050565b60008060006060848603121561087357600080fd5b61087c8461080b565b925061088a6020850161080b565b9150604084013590509250925092565b6000602082840312156108ac57600080fd5b5035919050565b6000602082840312156108c557600080fd5b61078e8261080b565b600080604083850312156108e157600080fd5b6108ea8361080b565b91506108f86020840161080b565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156103e2576103e2610901565b600181811c9082168061095757607f821691505b602082108103610990577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b818103818111156103e2576103e261090156fea164736f6c6343000813000a", -} - -var WETH9ABI = WETH9MetaData.ABI - -var WETH9Bin = WETH9MetaData.Bin - -func DeployWETH9(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *WETH9, error) { - parsed, err := WETH9MetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(WETH9Bin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &WETH9{address: address, abi: *parsed, WETH9Caller: WETH9Caller{contract: contract}, WETH9Transactor: WETH9Transactor{contract: contract}, WETH9Filterer: WETH9Filterer{contract: contract}}, nil -} - -type WETH9 struct { - address common.Address - abi abi.ABI - WETH9Caller - WETH9Transactor - WETH9Filterer -} - -type WETH9Caller struct { - contract *bind.BoundContract -} - -type WETH9Transactor struct { - contract *bind.BoundContract -} - -type WETH9Filterer struct { - contract *bind.BoundContract -} - -type WETH9Session struct { - Contract *WETH9 - CallOpts bind.CallOpts - TransactOpts bind.TransactOpts -} - -type WETH9CallerSession struct { - Contract *WETH9Caller - CallOpts bind.CallOpts -} - -type WETH9TransactorSession struct { - Contract *WETH9Transactor - TransactOpts bind.TransactOpts -} - -type WETH9Raw struct { - Contract *WETH9 -} - -type WETH9CallerRaw struct { - Contract *WETH9Caller -} - -type WETH9TransactorRaw struct { - Contract *WETH9Transactor -} - -func NewWETH9(address common.Address, backend bind.ContractBackend) (*WETH9, error) { - abi, err := abi.JSON(strings.NewReader(WETH9ABI)) - if err != nil { - return nil, err - } - contract, err := bindWETH9(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &WETH9{address: address, abi: abi, WETH9Caller: WETH9Caller{contract: contract}, WETH9Transactor: WETH9Transactor{contract: contract}, WETH9Filterer: WETH9Filterer{contract: contract}}, nil -} - -func NewWETH9Caller(address common.Address, caller bind.ContractCaller) (*WETH9Caller, error) { - contract, err := bindWETH9(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &WETH9Caller{contract: contract}, nil -} - -func NewWETH9Transactor(address common.Address, transactor bind.ContractTransactor) (*WETH9Transactor, error) { - contract, err := bindWETH9(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &WETH9Transactor{contract: contract}, nil -} - -func NewWETH9Filterer(address common.Address, filterer bind.ContractFilterer) (*WETH9Filterer, error) { - contract, err := bindWETH9(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &WETH9Filterer{contract: contract}, nil -} - -func bindWETH9(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := WETH9MetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -func (_WETH9 *WETH9Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _WETH9.Contract.WETH9Caller.contract.Call(opts, result, method, params...) -} - -func (_WETH9 *WETH9Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _WETH9.Contract.WETH9Transactor.contract.Transfer(opts) -} - -func (_WETH9 *WETH9Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _WETH9.Contract.WETH9Transactor.contract.Transact(opts, method, params...) -} - -func (_WETH9 *WETH9CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _WETH9.Contract.contract.Call(opts, result, method, params...) -} - -func (_WETH9 *WETH9TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _WETH9.Contract.contract.Transfer(opts) -} - -func (_WETH9 *WETH9TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _WETH9.Contract.contract.Transact(opts, method, params...) -} - -func (_WETH9 *WETH9Caller) Allowance(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address) (*big.Int, error) { - var out []interface{} - err := _WETH9.contract.Call(opts, &out, "allowance", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_WETH9 *WETH9Session) Allowance(arg0 common.Address, arg1 common.Address) (*big.Int, error) { - return _WETH9.Contract.Allowance(&_WETH9.CallOpts, arg0, arg1) -} - -func (_WETH9 *WETH9CallerSession) Allowance(arg0 common.Address, arg1 common.Address) (*big.Int, error) { - return _WETH9.Contract.Allowance(&_WETH9.CallOpts, arg0, arg1) -} - -func (_WETH9 *WETH9Caller) BalanceOf(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { - var out []interface{} - err := _WETH9.contract.Call(opts, &out, "balanceOf", arg0) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_WETH9 *WETH9Session) BalanceOf(arg0 common.Address) (*big.Int, error) { - return _WETH9.Contract.BalanceOf(&_WETH9.CallOpts, arg0) -} - -func (_WETH9 *WETH9CallerSession) BalanceOf(arg0 common.Address) (*big.Int, error) { - return _WETH9.Contract.BalanceOf(&_WETH9.CallOpts, arg0) -} - -func (_WETH9 *WETH9Caller) Decimals(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _WETH9.contract.Call(opts, &out, "decimals") - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_WETH9 *WETH9Session) Decimals() (uint8, error) { - return _WETH9.Contract.Decimals(&_WETH9.CallOpts) -} - -func (_WETH9 *WETH9CallerSession) Decimals() (uint8, error) { - return _WETH9.Contract.Decimals(&_WETH9.CallOpts) -} - -func (_WETH9 *WETH9Caller) Name(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _WETH9.contract.Call(opts, &out, "name") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -func (_WETH9 *WETH9Session) Name() (string, error) { - return _WETH9.Contract.Name(&_WETH9.CallOpts) -} - -func (_WETH9 *WETH9CallerSession) Name() (string, error) { - return _WETH9.Contract.Name(&_WETH9.CallOpts) -} - -func (_WETH9 *WETH9Caller) Symbol(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _WETH9.contract.Call(opts, &out, "symbol") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -func (_WETH9 *WETH9Session) Symbol() (string, error) { - return _WETH9.Contract.Symbol(&_WETH9.CallOpts) -} - -func (_WETH9 *WETH9CallerSession) Symbol() (string, error) { - return _WETH9.Contract.Symbol(&_WETH9.CallOpts) -} - -func (_WETH9 *WETH9Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _WETH9.contract.Call(opts, &out, "totalSupply") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_WETH9 *WETH9Session) TotalSupply() (*big.Int, error) { - return _WETH9.Contract.TotalSupply(&_WETH9.CallOpts) -} - -func (_WETH9 *WETH9CallerSession) TotalSupply() (*big.Int, error) { - return _WETH9.Contract.TotalSupply(&_WETH9.CallOpts) -} - -func (_WETH9 *WETH9Transactor) Approve(opts *bind.TransactOpts, guy common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.contract.Transact(opts, "approve", guy, wad) -} - -func (_WETH9 *WETH9Session) Approve(guy common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.Approve(&_WETH9.TransactOpts, guy, wad) -} - -func (_WETH9 *WETH9TransactorSession) Approve(guy common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.Approve(&_WETH9.TransactOpts, guy, wad) -} - -func (_WETH9 *WETH9Transactor) Deposit(opts *bind.TransactOpts) (*types.Transaction, error) { - return _WETH9.contract.Transact(opts, "deposit") -} - -func (_WETH9 *WETH9Session) Deposit() (*types.Transaction, error) { - return _WETH9.Contract.Deposit(&_WETH9.TransactOpts) -} - -func (_WETH9 *WETH9TransactorSession) Deposit() (*types.Transaction, error) { - return _WETH9.Contract.Deposit(&_WETH9.TransactOpts) -} - -func (_WETH9 *WETH9Transactor) Mint(opts *bind.TransactOpts, account common.Address, amount *big.Int) (*types.Transaction, error) { - return _WETH9.contract.Transact(opts, "mint", account, amount) -} - -func (_WETH9 *WETH9Session) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.Mint(&_WETH9.TransactOpts, account, amount) -} - -func (_WETH9 *WETH9TransactorSession) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.Mint(&_WETH9.TransactOpts, account, amount) -} - -func (_WETH9 *WETH9Transactor) Transfer(opts *bind.TransactOpts, dst common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.contract.Transact(opts, "transfer", dst, wad) -} - -func (_WETH9 *WETH9Session) Transfer(dst common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.Transfer(&_WETH9.TransactOpts, dst, wad) -} - -func (_WETH9 *WETH9TransactorSession) Transfer(dst common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.Transfer(&_WETH9.TransactOpts, dst, wad) -} - -func (_WETH9 *WETH9Transactor) TransferFrom(opts *bind.TransactOpts, src common.Address, dst common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.contract.Transact(opts, "transferFrom", src, dst, wad) -} - -func (_WETH9 *WETH9Session) TransferFrom(src common.Address, dst common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.TransferFrom(&_WETH9.TransactOpts, src, dst, wad) -} - -func (_WETH9 *WETH9TransactorSession) TransferFrom(src common.Address, dst common.Address, wad *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.TransferFrom(&_WETH9.TransactOpts, src, dst, wad) -} - -func (_WETH9 *WETH9Transactor) Withdraw(opts *bind.TransactOpts, wad *big.Int) (*types.Transaction, error) { - return _WETH9.contract.Transact(opts, "withdraw", wad) -} - -func (_WETH9 *WETH9Session) Withdraw(wad *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.Withdraw(&_WETH9.TransactOpts, wad) -} - -func (_WETH9 *WETH9TransactorSession) Withdraw(wad *big.Int) (*types.Transaction, error) { - return _WETH9.Contract.Withdraw(&_WETH9.TransactOpts, wad) -} - -func (_WETH9 *WETH9Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { - return _WETH9.contract.RawTransact(opts, nil) -} - -func (_WETH9 *WETH9Session) Receive() (*types.Transaction, error) { - return _WETH9.Contract.Receive(&_WETH9.TransactOpts) -} - -func (_WETH9 *WETH9TransactorSession) Receive() (*types.Transaction, error) { - return _WETH9.Contract.Receive(&_WETH9.TransactOpts) -} - -type WETH9ApprovalIterator struct { - Event *WETH9Approval - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *WETH9ApprovalIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(WETH9Approval) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - - select { - case log := <-it.logs: - it.Event = new(WETH9Approval) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -func (it *WETH9ApprovalIterator) Error() error { - return it.fail -} - -func (it *WETH9ApprovalIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type WETH9Approval struct { - Src common.Address - Guy common.Address - Wad *big.Int - Raw types.Log -} - -func (_WETH9 *WETH9Filterer) FilterApproval(opts *bind.FilterOpts, src []common.Address, guy []common.Address) (*WETH9ApprovalIterator, error) { - - var srcRule []interface{} - for _, srcItem := range src { - srcRule = append(srcRule, srcItem) - } - var guyRule []interface{} - for _, guyItem := range guy { - guyRule = append(guyRule, guyItem) - } - - logs, sub, err := _WETH9.contract.FilterLogs(opts, "Approval", srcRule, guyRule) - if err != nil { - return nil, err - } - return &WETH9ApprovalIterator{contract: _WETH9.contract, event: "Approval", logs: logs, sub: sub}, nil -} - -func (_WETH9 *WETH9Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *WETH9Approval, src []common.Address, guy []common.Address) (event.Subscription, error) { - - var srcRule []interface{} - for _, srcItem := range src { - srcRule = append(srcRule, srcItem) - } - var guyRule []interface{} - for _, guyItem := range guy { - guyRule = append(guyRule, guyItem) - } - - logs, sub, err := _WETH9.contract.WatchLogs(opts, "Approval", srcRule, guyRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(WETH9Approval) - if err := _WETH9.contract.UnpackLog(event, "Approval", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_WETH9 *WETH9Filterer) ParseApproval(log types.Log) (*WETH9Approval, error) { - event := new(WETH9Approval) - if err := _WETH9.contract.UnpackLog(event, "Approval", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type WETH9DepositIterator struct { - Event *WETH9Deposit - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *WETH9DepositIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(WETH9Deposit) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - - select { - case log := <-it.logs: - it.Event = new(WETH9Deposit) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -func (it *WETH9DepositIterator) Error() error { - return it.fail -} - -func (it *WETH9DepositIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type WETH9Deposit struct { - Dst common.Address - Wad *big.Int - Raw types.Log -} - -func (_WETH9 *WETH9Filterer) FilterDeposit(opts *bind.FilterOpts, dst []common.Address) (*WETH9DepositIterator, error) { - - var dstRule []interface{} - for _, dstItem := range dst { - dstRule = append(dstRule, dstItem) - } - - logs, sub, err := _WETH9.contract.FilterLogs(opts, "Deposit", dstRule) - if err != nil { - return nil, err - } - return &WETH9DepositIterator{contract: _WETH9.contract, event: "Deposit", logs: logs, sub: sub}, nil -} - -func (_WETH9 *WETH9Filterer) WatchDeposit(opts *bind.WatchOpts, sink chan<- *WETH9Deposit, dst []common.Address) (event.Subscription, error) { - - var dstRule []interface{} - for _, dstItem := range dst { - dstRule = append(dstRule, dstItem) - } - - logs, sub, err := _WETH9.contract.WatchLogs(opts, "Deposit", dstRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(WETH9Deposit) - if err := _WETH9.contract.UnpackLog(event, "Deposit", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_WETH9 *WETH9Filterer) ParseDeposit(log types.Log) (*WETH9Deposit, error) { - event := new(WETH9Deposit) - if err := _WETH9.contract.UnpackLog(event, "Deposit", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type WETH9TransferIterator struct { - Event *WETH9Transfer - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *WETH9TransferIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(WETH9Transfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - - select { - case log := <-it.logs: - it.Event = new(WETH9Transfer) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -func (it *WETH9TransferIterator) Error() error { - return it.fail -} - -func (it *WETH9TransferIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type WETH9Transfer struct { - Src common.Address - Dst common.Address - Wad *big.Int - Raw types.Log -} - -func (_WETH9 *WETH9Filterer) FilterTransfer(opts *bind.FilterOpts, src []common.Address, dst []common.Address) (*WETH9TransferIterator, error) { - - var srcRule []interface{} - for _, srcItem := range src { - srcRule = append(srcRule, srcItem) - } - var dstRule []interface{} - for _, dstItem := range dst { - dstRule = append(dstRule, dstItem) - } - - logs, sub, err := _WETH9.contract.FilterLogs(opts, "Transfer", srcRule, dstRule) - if err != nil { - return nil, err - } - return &WETH9TransferIterator{contract: _WETH9.contract, event: "Transfer", logs: logs, sub: sub}, nil -} - -func (_WETH9 *WETH9Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *WETH9Transfer, src []common.Address, dst []common.Address) (event.Subscription, error) { - - var srcRule []interface{} - for _, srcItem := range src { - srcRule = append(srcRule, srcItem) - } - var dstRule []interface{} - for _, dstItem := range dst { - dstRule = append(dstRule, dstItem) - } - - logs, sub, err := _WETH9.contract.WatchLogs(opts, "Transfer", srcRule, dstRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(WETH9Transfer) - if err := _WETH9.contract.UnpackLog(event, "Transfer", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_WETH9 *WETH9Filterer) ParseTransfer(log types.Log) (*WETH9Transfer, error) { - event := new(WETH9Transfer) - if err := _WETH9.contract.UnpackLog(event, "Transfer", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -type WETH9WithdrawalIterator struct { - Event *WETH9Withdrawal - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *WETH9WithdrawalIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(WETH9Withdrawal) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - - select { - case log := <-it.logs: - it.Event = new(WETH9Withdrawal) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -func (it *WETH9WithdrawalIterator) Error() error { - return it.fail -} - -func (it *WETH9WithdrawalIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type WETH9Withdrawal struct { - Src common.Address - Wad *big.Int - Raw types.Log -} - -func (_WETH9 *WETH9Filterer) FilterWithdrawal(opts *bind.FilterOpts, src []common.Address) (*WETH9WithdrawalIterator, error) { - - var srcRule []interface{} - for _, srcItem := range src { - srcRule = append(srcRule, srcItem) - } - - logs, sub, err := _WETH9.contract.FilterLogs(opts, "Withdrawal", srcRule) - if err != nil { - return nil, err - } - return &WETH9WithdrawalIterator{contract: _WETH9.contract, event: "Withdrawal", logs: logs, sub: sub}, nil -} - -func (_WETH9 *WETH9Filterer) WatchWithdrawal(opts *bind.WatchOpts, sink chan<- *WETH9Withdrawal, src []common.Address) (event.Subscription, error) { - - var srcRule []interface{} - for _, srcItem := range src { - srcRule = append(srcRule, srcItem) - } - - logs, sub, err := _WETH9.contract.WatchLogs(opts, "Withdrawal", srcRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(WETH9Withdrawal) - if err := _WETH9.contract.UnpackLog(event, "Withdrawal", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_WETH9 *WETH9Filterer) ParseWithdrawal(log types.Log) (*WETH9Withdrawal, error) { - event := new(WETH9Withdrawal) - if err := _WETH9.contract.UnpackLog(event, "Withdrawal", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -func (_WETH9 *WETH9) ParseLog(log types.Log) (generated.AbigenLog, error) { - switch log.Topics[0] { - case _WETH9.abi.Events["Approval"].ID: - return _WETH9.ParseApproval(log) - case _WETH9.abi.Events["Deposit"].ID: - return _WETH9.ParseDeposit(log) - case _WETH9.abi.Events["Transfer"].ID: - return _WETH9.ParseTransfer(log) - case _WETH9.abi.Events["Withdrawal"].ID: - return _WETH9.ParseWithdrawal(log) - - default: - return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) - } -} - -func (WETH9Approval) Topic() common.Hash { - return common.HexToHash("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925") -} - -func (WETH9Deposit) Topic() common.Hash { - return common.HexToHash("0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c") -} - -func (WETH9Transfer) Topic() common.Hash { - return common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") -} - -func (WETH9Withdrawal) Topic() common.Hash { - return common.HexToHash("0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65") -} - -func (_WETH9 *WETH9) Address() common.Address { - return _WETH9.address -} - -type WETH9Interface interface { - Allowance(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address) (*big.Int, error) - - BalanceOf(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) - - Decimals(opts *bind.CallOpts) (uint8, error) - - Name(opts *bind.CallOpts) (string, error) - - Symbol(opts *bind.CallOpts) (string, error) - - TotalSupply(opts *bind.CallOpts) (*big.Int, error) - - Approve(opts *bind.TransactOpts, guy common.Address, wad *big.Int) (*types.Transaction, error) - - Deposit(opts *bind.TransactOpts) (*types.Transaction, error) - - Mint(opts *bind.TransactOpts, account common.Address, amount *big.Int) (*types.Transaction, error) - - Transfer(opts *bind.TransactOpts, dst common.Address, wad *big.Int) (*types.Transaction, error) - - TransferFrom(opts *bind.TransactOpts, src common.Address, dst common.Address, wad *big.Int) (*types.Transaction, error) - - Withdraw(opts *bind.TransactOpts, wad *big.Int) (*types.Transaction, error) - - Receive(opts *bind.TransactOpts) (*types.Transaction, error) - - FilterApproval(opts *bind.FilterOpts, src []common.Address, guy []common.Address) (*WETH9ApprovalIterator, error) - - WatchApproval(opts *bind.WatchOpts, sink chan<- *WETH9Approval, src []common.Address, guy []common.Address) (event.Subscription, error) - - ParseApproval(log types.Log) (*WETH9Approval, error) - - FilterDeposit(opts *bind.FilterOpts, dst []common.Address) (*WETH9DepositIterator, error) - - WatchDeposit(opts *bind.WatchOpts, sink chan<- *WETH9Deposit, dst []common.Address) (event.Subscription, error) - - ParseDeposit(log types.Log) (*WETH9Deposit, error) - - FilterTransfer(opts *bind.FilterOpts, src []common.Address, dst []common.Address) (*WETH9TransferIterator, error) - - WatchTransfer(opts *bind.WatchOpts, sink chan<- *WETH9Transfer, src []common.Address, dst []common.Address) (event.Subscription, error) - - ParseTransfer(log types.Log) (*WETH9Transfer, error) - - FilterWithdrawal(opts *bind.FilterOpts, src []common.Address) (*WETH9WithdrawalIterator, error) - - WatchWithdrawal(opts *bind.WatchOpts, sink chan<- *WETH9Withdrawal, src []common.Address) (event.Subscription, error) - - ParseWithdrawal(log types.Log) (*WETH9Withdrawal, error) - - ParseLog(log types.Log) (generated.AbigenLog, error) - - Address() common.Address -} diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 7080ec31b26..3469f5ef4a2 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 @@ -117,4 +117,3 @@ vrfv2plus_wrapper_arbitrum: ../../contracts/solc/v0.8.19/VRFV2PlusWrapper_Arbitr vrfv2plus_wrapper_consumer_example: ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin aeb0c681fa264f90971f65cba1e8d41064948070b217c8204a80ac95e1fa2294 vrfv2plus_wrapper_load_test_consumer: ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin 5ca0223d3f6f6073ddfee4f9ddca13ea5f87297eb5f800359d7a1c41d04b6776 vrfv2plus_wrapper_optimism: ../../contracts/solc/v0.8.19/VRFV2PlusWrapper_Optimism/VRFV2PlusWrapper_Optimism.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapper_Optimism/VRFV2PlusWrapper_Optimism.bin 12a8c7a96716a5472a8ca712b10ab631085d4f5eb17bd5f7e0d2412556058ce9 -weth9_wrapper: ../../contracts/solc/v0.8.19/WETH9/WETH9.abi ../../contracts/solc/v0.8.19/WETH9/WETH9.bin 393b7b1ea2d1dc5a520a60cc6736dc489726cb0bd1481ea8b22d2872d4a510b1 diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index 7f1d3f02e91..339c27d98d5 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -57,7 +57,6 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/IChainModule/IChainModule.abi ../../contracts/solc/v0.8.19/IChainModule/IChainModule.bin IChainModule i_chain_module //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.abi ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.bin IAutomationV21PlusCommon i_automation_v21_plus_common //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/MockETHUSDAggregator/MockETHUSDAggregator.abi ../../contracts/solc/v0.8.19/MockETHUSDAggregator/MockETHUSDAggregator.bin MockETHUSDAggregator mock_ethusd_aggregator_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/WETH9/WETH9.abi ../../contracts/solc/v0.8.19/WETH9/WETH9.bin WETH9 weth9_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin ILogAutomation i_log_automation //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin AutomationForwarderLogic automation_forwarder_logic diff --git a/core/gethwrappers/ccip/generated/weth9/weth9.go b/core/gethwrappers/shared/generated/weth9/weth9.go similarity index 83% rename from core/gethwrappers/ccip/generated/weth9/weth9.go rename to core/gethwrappers/shared/generated/weth9/weth9.go index 34c1fd7fb8b..f8c1c3e157b 100644 --- a/core/gethwrappers/ccip/generated/weth9/weth9.go +++ b/core/gethwrappers/shared/generated/weth9/weth9.go @@ -32,7 +32,7 @@ var ( var WETH9MetaData = &bind.MetaData{ ABI: "[{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"allowance\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"guy\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"wad\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalSupply\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transfer\",\"inputs\":[{\"name\":\"dst\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"wad\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"src\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"dst\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"wad\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"wad\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"src\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"guy\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"wad\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"dst\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"wad\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"src\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"dst\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"wad\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Withdrawal\",\"inputs\":[{\"name\":\"src\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"wad\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x60806040523461011457610014600054610119565b601f81116100cb575b507f577261707065642045746865720000000000000000000000000000000000001a60005560015461004e90610119565b601f8111610081575b6008630ae8aa8960e31b016001556002805460ff19166012179055604051610a5a90816101548239f35b6001600052601f0160051c7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6908101905b8181106100bf5750610057565b600081556001016100b2565b60008052601f0160051c7f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563908101905b818110610108575061001d565b600081556001016100fb565b600080fd5b90600182811c92168015610149575b602083101461013357565b634e487b7160e01b600052602260045260246000fd5b91607f169161012856fe60806040526004361015610062575b361561001957600080fd5b33600052600360205260406000206100323482546108a0565b90556040513481527fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c60203392a2005b60003560e01c806306fdde0314610696578063095ea7b3146105ef57806318160ddd146105b557806323b872dd146105685780632e1a7d4d146104aa578063313ce5671461046b57806370a082311461040657806395d89b4114610208578063a9059cbb146101b8578063d0e30db0146101755763dd62ed3e0361000e57346101705760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101705761011761081e565b73ffffffffffffffffffffffffffffffffffffffff610134610841565b9116600052600460205273ffffffffffffffffffffffffffffffffffffffff604060002091166000526020526020604060002054604051908152f35b600080fd5b60007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101705733600052600360205260406000206100323482546108a0565b346101705760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101705760206101fe6101f461081e565b60243590336108ad565b6040519015158152f35b346101705760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610170576000604051908091600154928360011c600185169485156103fc575b6020821086146103cf57839495828552908160001461036f57506001146102f6575b5003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210176102c9576102c59250604052604051918291826107b6565b0390f35b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b600185528491507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b81831061035357505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610275565b602091935080600191548385880101520191019091839261031f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208581019190915291151560051b840190910191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09050610275565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b90607f1690610253565b346101705760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101705773ffffffffffffffffffffffffffffffffffffffff61045261081e565b1660005260036020526020604060002054604051908152f35b346101705760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017057602060ff60025416604051908152f35b346101705760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017057600435336000526003602052806040600020541061017057336000526003602052604060002061050a828254610864565b9055806000811561055f575b600080809381933390f115610553576040519081527f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b6560203392a2005b6040513d6000823e3d90fd5b506108fc610516565b346101705760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101705760206101fe6105a461081e565b6105ac610841565b604435916108ad565b346101705760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017057602047604051908152f35b346101705760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101705761062661081e565b73ffffffffffffffffffffffffffffffffffffffff6024359133600052600460205260406000208282166000526020528260406000205560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346101705760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101705760006040519080918154928360011c600185169485156107ac575b6020821086146103cf57839495828552908160001461036f5750600114610751575003601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210176102c9576102c59250604052604051918291826107b6565b848052602085208592505b81831061079057505081016020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610275565b602091935080600191548385880101520191019091839261075c565b90607f16906106e0565b9190916020815282519283602083015260005b8481106108085750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b80602080928401015160408286010152016107c9565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361017057565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361017057565b9190820391821161087157565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820180921161087157565b73ffffffffffffffffffffffffffffffffffffffff16908160005260036020528260406000205410610170573382141580610a03575b610963575b602073ffffffffffffffffffffffffffffffffffffffff7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9284600052600383526040600020610939878254610864565b90551693846000526003825260406000206109558282546108a0565b9055604051908152a3600190565b816000526004602052604060002073ffffffffffffffffffffffffffffffffffffffff3316600052602052826040600020541061017057602073ffffffffffffffffffffffffffffffffffffffff7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9284600052600483526040600020823316600052835260406000206109f8878254610864565b9055925050506108e8565b50816000526004602052604060002073ffffffffffffffffffffffffffffffffffffffff33166000526020526fffffffffffffffffffffffffffffffff60406000205414156108e356fea164736f6c634300081a000a", + Bin: "0x60c0604052600d60809081526c2bb930b83832b21022ba3432b960991b60a05260009061002c9082610114565b506040805180820190915260048152630ae8aa8960e31b60208201526001906100559082610114565b506002805460ff1916601217905534801561006f57600080fd5b506101d3565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061009f57607f821691505b6020821081036100bf57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561010f57600081815260208120601f850160051c810160208610156100ec5750805b601f850160051c820191505b8181101561010b578281556001016100f8565b5050505b505050565b81516001600160401b0381111561012d5761012d610075565b6101418161013b845461008b565b846100c5565b602080601f831160018114610176576000841561015e5750858301515b600019600386901b1c1916600185901b17855561010b565b600085815260208120601f198616915b828110156101a557888601518255948401946001909101908401610186565b50858210156101c35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6108ac806101e26000396000f3fe6080604052600436106100c05760003560e01c8063313ce56711610074578063a9059cbb1161004e578063a9059cbb146101fa578063d0e30db01461021a578063dd62ed3e1461022257600080fd5b8063313ce5671461018c57806370a08231146101b857806395d89b41146101e557600080fd5b806318160ddd116100a557806318160ddd1461012f57806323b872dd1461014c5780632e1a7d4d1461016c57600080fd5b806306fdde03146100d4578063095ea7b3146100ff57600080fd5b366100cf576100cd61025a565b005b600080fd5b3480156100e057600080fd5b506100e96102b5565b6040516100f69190610695565b60405180910390f35b34801561010b57600080fd5b5061011f61011a36600461072a565b610343565b60405190151581526020016100f6565b34801561013b57600080fd5b50475b6040519081526020016100f6565b34801561015857600080fd5b5061011f610167366004610754565b6103bd565b34801561017857600080fd5b506100cd610187366004610790565b6105c4565b34801561019857600080fd5b506002546101a69060ff1681565b60405160ff90911681526020016100f6565b3480156101c457600080fd5b5061013e6101d33660046107a9565b60036020526000908152604090205481565b3480156101f157600080fd5b506100e961066a565b34801561020657600080fd5b5061011f61021536600461072a565b610677565b6100cd61068b565b34801561022e57600080fd5b5061013e61023d3660046107c4565b600460209081526000928352604080842090915290825290205481565b3360009081526003602052604081208054349290610279908490610826565b909155505060405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a2565b600080546102c290610839565b80601f01602080910402602001604051908101604052809291908181526020018280546102ee90610839565b801561033b5780601f106103105761010080835404028352916020019161033b565b820191906000526020600020905b81548152906001019060200180831161031e57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103ab9086815260200190565b60405180910390a35060015b92915050565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120548211156103ef57600080fd5b73ffffffffffffffffffffffffffffffffffffffff84163314801590610455575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020546fffffffffffffffffffffffffffffffff14155b156104dd5773ffffffffffffffffffffffffffffffffffffffff8416600090815260046020908152604080832033845290915290205482111561049757600080fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600460209081526040808320338452909152812080548492906104d790849061088c565b90915550505b73ffffffffffffffffffffffffffffffffffffffff84166000908152600360205260408120805484929061051290849061088c565b909155505073ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120805484929061054c908490610826565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516105b291815260200190565b60405180910390a35060019392505050565b336000908152600360205260409020548111156105e057600080fd5b33600090815260036020526040812080548392906105ff90849061088c565b9091555050604051339082156108fc029083906000818181858888f19350505050158015610631573d6000803e3d6000fd5b5060405181815233907f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b659060200160405180910390a250565b600180546102c290610839565b60006106843384846103bd565b9392505050565b61069361025a565b565b600060208083528351808285015260005b818110156106c2578581018301518582016040015282016106a6565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461072557600080fd5b919050565b6000806040838503121561073d57600080fd5b61074683610701565b946020939093013593505050565b60008060006060848603121561076957600080fd5b61077284610701565b925061078060208501610701565b9150604084013590509250925092565b6000602082840312156107a257600080fd5b5035919050565b6000602082840312156107bb57600080fd5b61068482610701565b600080604083850312156107d757600080fd5b6107e083610701565b91506107ee60208401610701565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156103b7576103b76107f7565b600181811c9082168061084d57607f821691505b602082108103610886577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b818103818111156103b7576103b76107f756fea164736f6c6343000813000a", } var WETH9ABI = WETH9MetaData.ABI diff --git a/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 0e49e7b25e7..63299417b22 100644 --- a/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -12,3 +12,4 @@ multicall3: ../../../contracts/solc/vendor/Multicall3/Multicall3.sol/Multicall3. type_and_version: ../../../contracts/solc/shared/ITypeAndVersion/ITypeAndVersion.sol/ITypeAndVersion.abi.json ../../../contracts/solc/shared/ITypeAndVersion/ITypeAndVersion.sol/ITypeAndVersion.bin 21f6da4daa754971a4fdafea90ec64a77a5f03e62f9a9639802726b22eaa380a vrf_log_emitter: ../../../contracts/solc/shared/VRFLogEmitter/VRFLogEmitter.sol/VRFLogEmitter.abi.json ../../../contracts/solc/shared/VRFLogEmitter/VRFLogEmitter.sol/VRFLogEmitter.bin 46788c9519425dd23befdea8e561ee454dcb559f6a8fe70f4a092805574218f6 werc20_mock: ../../../contracts/solc/shared/WERC20Mock/WERC20Mock.sol/WERC20Mock.abi.json ../../../contracts/solc/shared/WERC20Mock/WERC20Mock.sol/WERC20Mock.bin f5ba13fc99c248354508e3bab6cd0fb66607d3b7377f59a1e80b930e96ed4f48 +weth9: ../../../contracts/solc/vendor/WETH9/WETH9.sol/WETH9.abi.json ../../../contracts/solc/vendor/WETH9/WETH9.sol/WETH9.bin 0a66cf864b2f0853d3d253feec9c65538eaf4419bd2c709d1fad7e546b7a7746 diff --git a/core/gethwrappers/shared/go_generate.go b/core/gethwrappers/shared/go_generate.go index 30ca631178d..332dd31b662 100644 --- a/core/gethwrappers/shared/go_generate.go +++ b/core/gethwrappers/shared/go_generate.go @@ -16,3 +16,4 @@ package gethwrappers //go:generate go run ../generation/wrap.go vendor ERC20 erc20 //go:generate go run ../generation/wrap.go vendor Multicall3 multicall3 +//go:generate go run ../generation/wrap.go vendor WETH9 weth9 diff --git a/core/services/ocr2/plugins/ccip/testhelpers/ccip_contracts.go b/core/services/ocr2/plugins/ccip/testhelpers/ccip_contracts.go index 985901c7b9f..22a87bc47e3 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/ccip_contracts.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/ccip_contracts.go @@ -42,8 +42,8 @@ import ( "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/weth9" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers" ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config" diff --git a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/ccip_contracts_1_4_0.go b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/ccip_contracts_1_4_0.go index 6ffd3b727fe..99caaa6f5da 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/ccip_contracts_1_4_0.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/ccip_contracts_1_4_0.go @@ -40,9 +40,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0" "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/weth9" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers" ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config" diff --git a/deployment/ccip/changeset/cs_prerequisites.go b/deployment/ccip/changeset/cs_prerequisites.go index da4f59c3eb6..94958d06f67 100644 --- a/deployment/ccip/changeset/cs_prerequisites.go +++ b/deployment/ccip/changeset/cs_prerequisites.go @@ -23,9 +23,9 @@ import ( "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" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" ) var ( diff --git a/deployment/ccip/changeset/state.go b/deployment/ccip/changeset/state.go index e95179db4de..164bdebd17d 100644 --- a/deployment/ccip/changeset/state.go +++ b/deployment/ccip/changeset/state.go @@ -40,28 +40,26 @@ import ( common_v1_0 "github.com/smartcontractkit/chainlink/deployment/common/view/v1_0" "github.com/smartcontractkit/chainlink/deployment/helpers" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_rmn_contract" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/registry_module_owner_custom" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/multicall3" + chain_selectors "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver" - capabilities_registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" - - chain_selectors "github.com/smartcontractkit/chain-selectors" - + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_rmn_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/nonce_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/registry_module_owner_custom" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_proxy_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_remote" "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/weth9" + capabilities_registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/aggregator_v3_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/multicall3" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" ) var ( diff --git a/deployment/ccip/changeset/token_info.go b/deployment/ccip/changeset/token_info.go index 71c23b7fb44..bdd12764051 100644 --- a/deployment/ccip/changeset/token_info.go +++ b/deployment/ccip/changeset/token_info.go @@ -11,8 +11,8 @@ import ( "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" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" ) type TokenSymbol string diff --git a/integration-tests/ccip-tests/contracts/contract_deployer.go b/integration-tests/ccip-tests/contracts/contract_deployer.go index f564ab6244c..13525422bed 100644 --- a/integration-tests/ccip-tests/contracts/contract_deployer.go +++ b/integration-tests/ccip-tests/contracts/contract_deployer.go @@ -48,12 +48,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool_1_4_0" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool_1_4_0" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/erc20" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/mock_v3_aggregator_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/type_and_version" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers" ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers" diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index bd7a88cd2e3..043eb4ce06f 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -25,7 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/counter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_ethusd_aggregator_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/weth9_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" contractsethereum "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" @@ -1481,22 +1481,22 @@ func (e *EthereumFunctionsLoadTestClient) SendRequestWithDONHostedSecrets(times // EthereumWETHToken represents a WETH address type EthereumWETHToken struct { client *seth.Client - instance *weth9_wrapper.WETH9 + instance *weth9.WETH9 address common.Address l zerolog.Logger } func DeployWETHTokenContract(l zerolog.Logger, client *seth.Client) (*EthereumWETHToken, error) { - wethTokenAbi, err := weth9_wrapper.WETH9MetaData.GetAbi() + wethTokenAbi, err := weth9.WETH9MetaData.GetAbi() if err != nil { return &EthereumWETHToken{}, fmt.Errorf("failed to get WETH token ABI: %w", err) } - wethDeploymentData, err := client.DeployContract(client.NewTXOpts(), "WETHToken", *wethTokenAbi, common.FromHex(weth9_wrapper.WETH9MetaData.Bin)) + wethDeploymentData, err := client.DeployContract(client.NewTXOpts(), "WETHToken", *wethTokenAbi, common.FromHex(weth9.WETH9MetaData.Bin)) if err != nil { return &EthereumWETHToken{}, fmt.Errorf("WETH token instance deployment failed: %w", err) } - wethToken, err := weth9_wrapper.NewWETH9(wethDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, client)) + wethToken, err := weth9.NewWETH9(wethDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, client)) if err != nil { return &EthereumWETHToken{}, fmt.Errorf("failed to instantiate WETHToken instance: %w", err) } @@ -1510,15 +1510,15 @@ func DeployWETHTokenContract(l zerolog.Logger, client *seth.Client) (*EthereumWE } func LoadWETHTokenContract(l zerolog.Logger, client *seth.Client, address common.Address) (*EthereumWETHToken, error) { - abi, err := weth9_wrapper.WETH9MetaData.GetAbi() + abi, err := weth9.WETH9MetaData.GetAbi() if err != nil { return &EthereumWETHToken{}, fmt.Errorf("failed to get WETH token ABI: %w", err) } client.ContractStore.AddABI("WETHToken", *abi) - client.ContractStore.AddBIN("WETHToken", common.FromHex(weth9_wrapper.WETH9MetaData.Bin)) + client.ContractStore.AddBIN("WETHToken", common.FromHex(weth9.WETH9MetaData.Bin)) - wethToken, err := weth9_wrapper.NewWETH9(address, wrappers.MustNewWrappedContractBackend(nil, client)) + wethToken, err := weth9.NewWETH9(address, wrappers.MustNewWrappedContractBackend(nil, client)) if err != nil { return &EthereumWETHToken{}, fmt.Errorf("failed to instantiate WETHToken instance: %w", err) } diff --git a/integration-tests/smoke/ccip/ccip_fees_test.go b/integration-tests/smoke/ccip/ccip_fees_test.go index a7872c3930d..db323783cfd 100644 --- a/integration-tests/smoke/ccip/ccip_fees_test.go +++ b/integration-tests/smoke/ccip/ccip_fees_test.go @@ -18,8 +18,8 @@ import ( testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/weth9_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/evm/assets" ) @@ -330,7 +330,7 @@ func runFeeTokenTestCase(tc feeTokenTestCase) { if tc.feeToken != common.HexToAddress("0x0") { if tc.feeToken == state.Chains[tc.src].Weth9.Address() { // Deposit some ETH into the WETH contract - weth9, err := weth9_wrapper.NewWETH9(state.Chains[tc.src].Weth9.Address(), srcChain.Client) + weth9, err := weth9.NewWETH9(state.Chains[tc.src].Weth9.Address(), srcChain.Client) require.NoError(tc.t, err) balance, err := srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) From 457927cd91e3d2127d30f49117718f4902df21b6 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Thu, 30 Jan 2025 17:21:18 +0100 Subject: [PATCH 12/43] [TT-1847] keystone smoke use chainlink deployment (#16123) * WIP, almost working... last step fails, when forwarder calls DF cache * working version * use newer PoR workflow * now its broken again * Update gethwrappers * go back to previous config, where all steps were correcty configured * use older config * fix port * use debug consumer contract * WORKING VERSION * remove mock streams capability * passes with workflow registry deployed with c/d * passes with keystone consumer deployed with c/d * passes with keystone forwarder deployed with c/d * remove some deps * allow to use chainlink-cli * restore old KeystoneFeedsConsumer.sol contract * try to run the test in CI * fix integration workflow * move the function * use existing env vars to get the image, use e2e tests workflow version that sets GH_TOKEN as env var available to tests * add missing PRIVATE_KEY env var * pass optional roles for GATI to be able to read from repositories * add some comments, update e2e workflow commit * add comments * fix integration tests workflow file * newer workflow version * update token name and workflow version * do not use chainlink CLI in the CI for now (we need a token that can access it) * fix env var name in CI * fix capability reference * clean up the workflow test * move capability test to smoke subfolder * restore old versions of feeds consumer wrapper * rename GITHUB_TOKEN env var to GITHUB_API_TOKEN * try one more approach to resolving placeholder env var * adjust env file to new location * revert testing-related changes to integration tests workflow * fix lints * use function from chainlink-common to generate workflow id, define new constants for binary file names * add JD * use C/D to setup all contracts * add extra debug information * fix lint * poll config every 500ms * change polling interval to 1s * fix config polling intervnal * use only chainlink/deployments when interacting with contract * JD is failing to create jobs due to a bug and authorization issue * do not use JD to setup jobs * CR changes * adjust to latest changes, move some configs to TOML * CR changes * move comments around * add test modification guideline and better debugging * fix config validations * fix lints * use fixed JD version in the CI * remove workflow registration artifact file * restore older environment file * get p2p ide from node labels, more comments, use contractset * fix lints and remove superfluous methods * dynamic transmission schedule * use configurable workflow_id also when registering the workflow * remove unused struct * trigger pipeline * add comment explaining OCR3 settings --------- Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> --- .github/e2e-tests.yml | 1 + deployment/environment/devenv/don.go | 50 +- deployment/environment/devenv/jd.go | 2 +- deployment/keystone/changeset/compatiblity.go | 3 + .../keystone/changeset/internal/types.go | 4 + .../smoke/capabilities/environment-ci.toml | 10 +- .../smoke/capabilities/environment.toml | 11 +- .../smoke/capabilities/workflow_test.go | 850 ++++++++---------- 8 files changed, 458 insertions(+), 473 deletions(-) diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index 7c75d44fa92..707ef8c6027 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -194,6 +194,7 @@ runner-test-matrix: pyroscope_env: ci-smoke-capabilities-evm-simulated test_env_vars: E2E_TEST_CHAINLINK_VERSION: '{{ env.DEFAULT_CHAINLINK_PLUGINS_VERSION }}' # This is the chainlink version that has the plugins + E2E_JD_VERSION: 0.6.0 # there is no latest tag for this repo, so we need to specify the version GITHUB_READ_TOKEN: '{{ env.GITHUB_API_TOKEN }}' # GATI-provided token that can read from capabilities and dev-platform repos IS_CI: "true" CTF_CONFIGS: "environment-ci.toml" diff --git a/deployment/environment/devenv/don.go b/deployment/environment/devenv/don.go index a8912254d1d..ea0a43924e3 100644 --- a/deployment/environment/devenv/don.go +++ b/deployment/environment/devenv/don.go @@ -24,6 +24,7 @@ import ( const ( NodeLabelKeyType = "type" + NodeLabelP2PIDType = "p2p_id" NodeLabelValueBootstrap = "bootstrap" NodeLabelValuePlugin = "plugin" ) @@ -68,7 +69,7 @@ func (don *DON) ReplayAllLogs(blockbyChain map[uint64]uint64) error { func (don *DON) NodeIds() []string { var nodeIds []string for _, node := range don.Nodes { - nodeIds = append(nodeIds, node.NodeId) + nodeIds = append(nodeIds, node.NodeID) } return nodeIds } @@ -130,6 +131,15 @@ func NewRegisteredDON(ctx context.Context, nodeInfo []NodeInfo, jd JobDistributo // multi address is not applicable for non-bootstrap nodes // explicitly set it to empty string to denote that node.multiAddr = "" + + // set admin address for non-bootstrap nodes + node.adminAddr = info.AdminAddr + + // capability registry requires non-null admin address; use arbitrary default value if node is not configured + if info.AdminAddr == "" { + node.adminAddr = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + } + node.labels = append(node.labels, &ptypes.Label{ Key: NodeLabelKeyType, Value: ptr(NodeLabelValuePlugin), @@ -167,15 +177,16 @@ func NewNode(nodeInfo NodeInfo) (*Node, error) { } type Node struct { - NodeId string // node id returned by job distributor after node is registered with it - JDId string // job distributor id returned by node after Job distributor is created in node - Name string // name of the node - AccountAddr map[uint64]string // chain id to node's account address mapping for supported chains - gqlClient client.Client // graphql client to interact with the node - restClient *clclient.ChainlinkClient // rest client to interact with the node - labels []*ptypes.Label // labels with which the node is registered with the job distributor - adminAddr string // admin address to send payments to, applicable only for non-bootstrap nodes - multiAddr string // multi address denoting node's FQN (needed for deriving P2PBootstrappers in OCR), applicable only for bootstrap nodes + NodeID string // node id returned by job distributor after node is registered with it + JDId string // job distributor id returned by node after Job distributor is created in node + Name string // name of the node + AccountAddr map[uint64]string // chain id to node's account address mapping for supported chains + Ocr2KeyBundleID string // OCR2 key bundle id of the node + gqlClient client.Client // graphql client to interact with the node + restClient *clclient.ChainlinkClient // rest client to interact with the node + labels []*ptypes.Label // labels with which the node is registered with the job distributor + adminAddr string // admin address to send payments to, applicable only for non-bootstrap nodes + multiAddr string // multi address denoting node's FQN (needed for deriving P2PBootstrappers in OCR), applicable only for bootstrap nodes } type JDChainConfigInput struct { @@ -183,6 +194,10 @@ type JDChainConfigInput struct { ChainType string } +func (n *Node) Labels() []*ptypes.Label { + return n.labels +} + // CreateCCIPOCRSupportedChains creates a JobDistributorChainConfig for the node. // It works under assumption that the node is already registered with the job distributor. // It expects bootstrap nodes to have label with key "type" and value as "bootstrap". @@ -234,6 +249,7 @@ func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []JDChai if ocr2BundleId == "" { return fmt.Errorf("no OCR2 key bundle id found for node %s", n.Name) } + n.Ocr2KeyBundleID = ocr2BundleId // fetch node labels to know if the node is bootstrap or plugin isBootstrap := false for _, label := range n.labels { @@ -248,7 +264,7 @@ func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []JDChai // check the node chain config to see if this chain already exists nodeChainConfigs, err := jd.ListNodeChainConfigs(context.Background(), &nodev1.ListNodeChainConfigsRequest{ Filter: &nodev1.ListNodeChainConfigsRequest_Filter{ - NodeIds: []string{n.NodeId}, + NodeIds: []string{n.NodeID}, }}) if err != nil { return retry.RetryableError(fmt.Errorf("failed to list node chain configs for node %s, retrying..: %w", n.Name, err)) @@ -344,7 +360,7 @@ func (n *Node) RegisterNodeToJobDistributor(ctx context.Context, jd JobDistribut return fmt.Errorf("no peer id found for node %s", n.Name) } n.labels = append(n.labels, &ptypes.Label{ - Key: "p2p_id", + Key: NodeLabelP2PIDType, Value: peerID, }) @@ -361,7 +377,7 @@ func (n *Node) RegisterNodeToJobDistributor(ctx context.Context, jd JobDistribut Filter: &nodev1.ListNodesRequest_Filter{ Selectors: []*ptypes.Selector{ { - Key: "p2p_id", + Key: NodeLabelP2PIDType, Op: ptypes.SelectorOp_EQ, Value: peerID, }, @@ -375,7 +391,7 @@ func (n *Node) RegisterNodeToJobDistributor(ctx context.Context, jd JobDistribut if len(nodes) == 0 { return fmt.Errorf("failed to find node: %v", n.Name) } - n.NodeId = nodes[0].Id + n.NodeID = nodes[0].Id return nil } else if err != nil { return fmt.Errorf("failed to register node %s: %w", n.Name, err) @@ -383,7 +399,7 @@ func (n *Node) RegisterNodeToJobDistributor(ctx context.Context, jd JobDistribut if registerResponse.GetNode().GetId() == "" { return fmt.Errorf("no node id returned from job distributor for node %s", n.Name) } - n.NodeId = registerResponse.GetNode().GetId() + n.NodeID = registerResponse.GetNode().GetId() return nil } @@ -431,13 +447,13 @@ func (n *Node) SetUpAndLinkJobDistributor(ctx context.Context, jd JobDistributor // wait for the node to connect to the job distributor err = retry.Do(ctx, retry.WithMaxDuration(1*time.Minute, retry.NewFibonacci(1*time.Second)), func(ctx context.Context) error { getRes, err := jd.GetNode(ctx, &nodev1.GetNodeRequest{ - Id: n.NodeId, + Id: n.NodeID, }) if err != nil { return retry.RetryableError(fmt.Errorf("failed to get node %s: %w", n.Name, err)) } if getRes.GetNode() == nil { - return fmt.Errorf("no node found for node id %s", n.NodeId) + return fmt.Errorf("no node found for node id %s", n.NodeID) } if !getRes.GetNode().IsConnected { return retry.RetryableError(fmt.Errorf("node %s not connected to job distributor", n.Name)) diff --git a/deployment/environment/devenv/jd.go b/deployment/environment/devenv/jd.go index 755f5cc70cd..e3feb35f7dd 100644 --- a/deployment/environment/devenv/jd.go +++ b/deployment/environment/devenv/jd.go @@ -166,7 +166,7 @@ func (jd JobDistributor) ProposeJob(ctx context.Context, in *jobv1.ProposeJobReq return res, nil } for _, node := range jd.don.Nodes { - if node.NodeId != in.NodeId { + if node.NodeID != in.NodeId { continue } // TODO : is there a way to accept the job with proposal id? diff --git a/deployment/keystone/changeset/compatiblity.go b/deployment/keystone/changeset/compatiblity.go index 67b799a02ce..a353e1acc92 100644 --- a/deployment/keystone/changeset/compatiblity.go +++ b/deployment/keystone/changeset/compatiblity.go @@ -79,6 +79,9 @@ var RegisterDons = internal.RegisterDons // DONToRegister is the minimal information needed to register a DON with the capabilities registry type DONToRegister = internal.DONToRegister +// NOP is a node operator profile, required to register a node with the capabilities registry +type NOP = internal.NOP + // ConfigureContractsRequest is a request to configure ALL the contracts type ConfigureContractsRequest = internal.ConfigureContractsRequest diff --git a/deployment/keystone/changeset/internal/types.go b/deployment/keystone/changeset/internal/types.go index 66a512468ea..1b1faccca5b 100644 --- a/deployment/keystone/changeset/internal/types.go +++ b/deployment/keystone/changeset/internal/types.go @@ -255,6 +255,10 @@ func NewRegisteredDon(env deployment.Environment, cfg RegisteredDonConfig) (*Reg } capReg := r.ContractSets[cfg.RegistryChainSel].CapabilitiesRegistry + if capReg == nil { + return nil, errors.New("capabilities registry not found in contract sets") + } + di, err := capReg.GetDONs(nil) if err != nil { return nil, fmt.Errorf("failed to get dons: %w", err) diff --git a/integration-tests/smoke/capabilities/environment-ci.toml b/integration-tests/smoke/capabilities/environment-ci.toml index 67e3c7842d0..4ba6cbdc1ac 100644 --- a/integration-tests/smoke/capabilities/environment-ci.toml +++ b/integration-tests/smoke/capabilities/environment-ci.toml @@ -3,13 +3,21 @@ type = "anvil" docker_cmd_params = ["-b", "5"] +[jd] + image = "replace-me" + [workflow_config] + don_id = 1 + workflow_name = "abcdefgasd" + # without 0x prefix! + feed_id = "018bfe8840700040000000000000000000000000000000000000000000000000" + use_chainlink_cli = false use_existing = true [workflow_config.existing] binary_url = "https://gist.githubusercontent.com/Tofel/8a39af5b68c213d2200446c175b5c99e/raw/cb7b2a56b37e333fe0bdce07b79538c4ce332f5f/binary.wasm.br" - config_url = "https://gist.githubusercontent.com/Tofel/5b9ccb1cc1a5aa68aa08a5b2066d60a7/raw/7dcdda86b9d50d17029614f370fd2acab1e7fb27/config.json3175390991" + config_url = "https://gist.githubusercontent.com/Tofel/19c80e6297914a79449f916e5e65dfdd/raw/1344c259ef7e970dbabaa1e9e885845b8eba5da9/config.json3674692696" [nodeset] nodes = 5 diff --git a/integration-tests/smoke/capabilities/environment.toml b/integration-tests/smoke/capabilities/environment.toml index 11d3784f50c..b6db7e5676d 100644 --- a/integration-tests/smoke/capabilities/environment.toml +++ b/integration-tests/smoke/capabilities/environment.toml @@ -3,13 +3,22 @@ type = "anvil" docker_cmd_params = ["-b", "5"] +[jd] + # change to your version + image = "jd-test-1:latest" + [workflow_config] + don_id = 1 + workflow_name = "abcdefgasd" + # without 0x prefix! + feed_id = "018bfe8840700040000000000000000000000000000000000000000000000000" + use_chainlink_cli = true use_existing = true [workflow_config.existing] binary_url = "https://gist.githubusercontent.com/Tofel/8a39af5b68c213d2200446c175b5c99e/raw/cb7b2a56b37e333fe0bdce07b79538c4ce332f5f/binary.wasm.br" - config_url = "https://gist.githubusercontent.com/Tofel/5b9ccb1cc1a5aa68aa08a5b2066d60a7/raw/7dcdda86b9d50d17029614f370fd2acab1e7fb27/config.json3175390991" + config_url = "https://gist.githubusercontent.com/Tofel/19c80e6297914a79449f916e5e65dfdd/raw/1344c259ef7e970dbabaa1e9e885845b8eba5da9/config.json3674692696" [workflow_config.chainlink_cli] folder_location = "path-to-folder-with-main.go-of-your-workflow" diff --git a/integration-tests/smoke/capabilities/workflow_test.go b/integration-tests/smoke/capabilities/workflow_test.go index 5e4dbbefc33..c9fa136c597 100644 --- a/integration-tests/smoke/capabilities/workflow_test.go +++ b/integration-tests/smoke/capabilities/workflow_test.go @@ -3,23 +3,21 @@ package capabilities_test import ( "bufio" "bytes" - "cmp" "context" "crypto/sha256" "encoding/base64" - "encoding/binary" "encoding/hex" "encoding/json" "fmt" "io" - "math" "math/big" "net/http" + "net/url" "os" "os/exec" "path/filepath" "regexp" - "slices" + "strconv" "strings" "sync" "testing" @@ -33,18 +31,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/oauth2" + "google.golang.org/grpc/credentials/insecure" - "github.com/smartcontractkit/libocr/offchainreporting2/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2/types" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" - ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" - - geth_types "github.com/ethereum/go-ethereum/core/types" chainselectors "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-testing-framework/framework" "github.com/smartcontractkit/chainlink-testing-framework/framework/clclient" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/jd" ns "github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set" "github.com/smartcontractkit/chainlink-testing-framework/lib/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/seth" @@ -53,69 +47,29 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" pkgworkflows "github.com/smartcontractkit/chainlink-common/pkg/workflows" - cr_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/feeds_consumer" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/forwarder" - ocr3_capability "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/ocr3_capability" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/workflow/generated/workflow_registry_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" + capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/lib/config" + "github.com/smartcontractkit/chainlink/deployment/environment/devenv" + "github.com/smartcontractkit/chainlink/deployment/environment/nodeclient" keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" workflow_registry_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/workflowregistry" + kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" ) -// Copying this to avoid dependency on the core repo -func GetChainType(chainType string) (uint8, error) { - switch chainType { - case "evm": - return 1, nil - // case Solana: - // return 2, nil - // case Cosmos: - // return 3, nil - // case StarkNet: - // return 4, nil - // case Aptos: - // return 5, nil - default: - return 0, fmt.Errorf("unexpected chaintype.ChainType: %#v", chainType) - } -} - -// Copying this to avoid dependency on the core repo -func MarshalMultichainPublicKey(ost map[string]types.OnchainPublicKey) (types.OnchainPublicKey, error) { - pubKeys := make([][]byte, 0, len(ost)) - for k, pubKey := range ost { - typ, err := GetChainType(k) - if err != nil { - // skipping unknown key type - continue - } - buf := new(bytes.Buffer) - if err = binary.Write(buf, binary.LittleEndian, typ); err != nil { - return nil, err - } - length := len(pubKey) - if length < 0 || length > math.MaxUint16 { - return nil, errors.New("pubKey doesn't fit into uint16") - } - if err = binary.Write(buf, binary.LittleEndian, uint16(length)); err != nil { - return nil, err - } - _, _ = buf.Write(pubKey) - pubKeys = append(pubKeys, buf.Bytes()) - } - // sort keys based on encoded type to make encoding deterministic - slices.SortFunc(pubKeys, func(a, b []byte) int { return cmp.Compare(a[0], b[0]) }) - return bytes.Join(pubKeys, nil), nil -} - type WorkflowConfig struct { UseChainlinkCLI bool `toml:"use_chainlink_cli"` ChainlinkCLI *ChainlinkCLIConfig `toml:"chainlink_cli"` UseExising bool `toml:"use_existing"` Existing *ExistingWorkflowConfig `toml:"existing"` + // id, which will be used, when registering the DON with the workflow registry, + // and when instructing the Gateway job on the bootstrap node as to which workflow to run. + DonID uint32 `toml:"don_id" validate:"required"` + WorkflowName string `toml:"workflow_name" validate:"required" ` + FeedID string `toml:"feed_id" validate:"required"` } type ExistingWorkflowConfig struct { @@ -131,33 +85,7 @@ type WorkflowTestConfig struct { BlockchainA *blockchain.Input `toml:"blockchain_a" validate:"required"` NodeSet *ns.Input `toml:"nodeset" validate:"required"` WorkflowConfig *WorkflowConfig `toml:"workflow_config" validate:"required"` -} - -type OCR3Config struct { - Signers [][]byte - Transmitters []common.Address - F uint8 - OnchainConfig []byte - OffchainConfigVersion uint64 - OffchainConfig []byte -} - -type NodeInfo struct { - OcrKeyBundleID string - TransmitterAddress string - PeerID string - Signer common.Address - OffchainPublicKey [32]byte - OnchainPublicKey types.OnchainPublicKey - ConfigEncryptionPublicKey [32]byte -} - -func extractKey(value string) string { - parts := strings.Split(value, "_") - if len(parts) > 1 { - return parts[len(parts)-1] - } - return value + JD *jd.Input `toml:"jd" validate:"required"` } func downloadGHAssetFromLatestRelease(owner, repository, releaseType, assetName, ghToken string) ([]byte, error) { @@ -228,118 +156,6 @@ func downloadGHAssetFromLatestRelease(owner, repository, releaseType, assetName, return content, errors.New("no automatic tag provided") } -func getNodesInfo( - t *testing.T, - nodes []*clclient.ChainlinkClient, -) (nodesInfo []NodeInfo) { - nodesInfo = make([]NodeInfo, len(nodes)) - - for i, node := range nodes { - // OCR Keys - ocr2Keys, err := node.MustReadOCR2Keys() - require.NoError(t, err) - nodesInfo[i].OcrKeyBundleID = ocr2Keys.Data[0].ID - - firstOCR2Key := ocr2Keys.Data[0].Attributes - nodesInfo[i].Signer = common.HexToAddress(extractKey(firstOCR2Key.OnChainPublicKey)) - - pubKeys := make(map[string]types.OnchainPublicKey) - ethOnchainPubKey, err := hex.DecodeString(extractKey(firstOCR2Key.OnChainPublicKey)) - require.NoError(t, err) - pubKeys["evm"] = ethOnchainPubKey - - multichainPubKey, err := MarshalMultichainPublicKey(pubKeys) - require.NoError(t, err) - nodesInfo[i].OnchainPublicKey = multichainPubKey - - offchainPublicKeyBytes, err := hex.DecodeString(extractKey(firstOCR2Key.OffChainPublicKey)) - require.NoError(t, err) - var offchainPublicKey [32]byte - copy(offchainPublicKey[:], offchainPublicKeyBytes) - nodesInfo[i].OffchainPublicKey = offchainPublicKey - - sharedSecretEncryptionPublicKeyBytes, err := hex.DecodeString(extractKey(firstOCR2Key.ConfigPublicKey)) - require.NoError(t, err) - var sharedSecretEncryptionPublicKey [32]byte - copy(sharedSecretEncryptionPublicKey[:], sharedSecretEncryptionPublicKeyBytes) - nodesInfo[i].ConfigEncryptionPublicKey = sharedSecretEncryptionPublicKey - - // ETH Keys - ethKeys, err := node.MustReadETHKeys() - require.NoError(t, err) - nodesInfo[i].TransmitterAddress = ethKeys.Data[0].Attributes.Address - - // P2P Keys - p2pKeys, err := node.MustReadP2PKeys() - require.NoError(t, err) - nodesInfo[i].PeerID = p2pKeys.Data[0].Attributes.PeerID - } - - return nodesInfo -} - -func generateOCR3Config( - t *testing.T, - nodesInfo []NodeInfo, -) (config *OCR3Config) { - oracleIdentities := []confighelper.OracleIdentityExtra{} - transmissionSchedule := []int{} - - for _, nodeInfo := range nodesInfo { - transmissionSchedule = append(transmissionSchedule, 1) - oracleIdentity := confighelper.OracleIdentityExtra{} - oracleIdentity.OffchainPublicKey = nodeInfo.OffchainPublicKey - oracleIdentity.OnchainPublicKey = nodeInfo.OnchainPublicKey - oracleIdentity.ConfigEncryptionPublicKey = nodeInfo.ConfigEncryptionPublicKey - oracleIdentity.PeerID = nodeInfo.PeerID - oracleIdentity.TransmitAccount = types.Account(nodeInfo.TransmitterAddress) - oracleIdentities = append(oracleIdentities, oracleIdentity) - } - - maxDurationInitialization := 10 * time.Second - - signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig, err := ocr3confighelper.ContractSetConfigArgsForTests( - 5*time.Second, // DeltaProgress: Time between rounds - 5*time.Second, // DeltaResend: Time between resending unconfirmed transmissions - 5*time.Second, // DeltaInitial: Initial delay before starting the first round - 2*time.Second, // DeltaRound: Time between rounds within an epoch - 500*time.Millisecond, // DeltaGrace: Grace period for delayed transmissions - 1*time.Second, // DeltaCertifiedCommitRequest: Time between certified commit requests - 30*time.Second, // DeltaStage: Time between stages of the protocol - uint64(10), // MaxRoundsPerEpoch: Maximum number of rounds per epoch - transmissionSchedule, // TransmissionSchedule: Transmission schedule - oracleIdentities, // Oracle identities with their public keys - nil, // Plugin config (empty for now) - &maxDurationInitialization, // MaxDurationInitialization: ??? - 1*time.Second, // MaxDurationQuery: Maximum duration for querying - 1*time.Second, // MaxDurationObservation: Maximum duration for observation - 1*time.Second, // MaxDurationAccept: Maximum duration for acceptance - 1*time.Second, // MaxDurationTransmit: Maximum duration for transmission - 1, // F: Maximum number of faulty oracles - nil, // OnChain config (empty for now) - ) - require.NoError(t, err) - - signerAddresses := [][]byte{} - for _, signer := range signers { - signerAddresses = append(signerAddresses, signer) - } - - transmitterAddresses := []common.Address{} - for _, transmitter := range transmitters { - transmitterAddresses = append(transmitterAddresses, common.HexToAddress(string(transmitter))) - } - - return &OCR3Config{ - Signers: signerAddresses, - Transmitters: transmitterAddresses, - F: f, - OnchainConfig: onchainConfig, - OffchainConfigVersion: offchainConfigVersion, - OffchainConfig: offchainConfig, - } -} - func GenerateWorkflowIDFromStrings(owner string, name string, workflow []byte, config []byte, secretsURL string) (string, error) { ownerWithoutPrefix := owner if strings.HasPrefix(owner, "0x") { @@ -454,9 +270,11 @@ type PoRWorkflowConfig struct { } const ( - chainlinkCliAssetFile = "cre_v1.0.2_linux_amd64.tar.gz" - cronCapabilityAssetFile = "amd64_cron" - ghReadTokenEnvVarName = "GITHUB_READ_TOKEN" + chainlinkCliAssetFile = "cre_v1.0.2_linux_amd64.tar.gz" + cronCapabilityAssetFile = "amd64_cron" + e2eJobDistributorImageEnvVarName = "E2E_JD_IMAGE" + e2eJobDistributorVersionEnvVarName = "E2E_JD_VERSION" + ghReadTokenEnvVarName = "GITHUB_READ_TOKEN" ) func downloadAndInstallChainlinkCLI(ghToken string) error { @@ -529,6 +347,20 @@ func validateInputsAndEnvVars(t *testing.T, testConfig *WorkflowTestConfig) { // we cannot execute this part in workflow steps (it doesn't support any pre-execution hooks) require.NotEmpty(t, os.Getenv(ctfconfig.E2E_TEST_CHAINLINK_IMAGE_ENV), "missing env var: "+ctfconfig.E2E_TEST_CHAINLINK_IMAGE_ENV) require.NotEmpty(t, os.Getenv(ctfconfig.E2E_TEST_CHAINLINK_VERSION_ENV), "missing env var: "+ctfconfig.E2E_TEST_CHAINLINK_VERSION_ENV) + require.NotEmpty(t, os.Getenv(e2eJobDistributorImageEnvVarName), "missing env var: "+e2eJobDistributorImageEnvVarName) + require.NotEmpty(t, os.Getenv(e2eJobDistributorVersionEnvVarName), "missing env var: "+e2eJobDistributorVersionEnvVarName) + + // disabled until we can figure out how to generate a gist read:write token in CI + /* + This test can be run in two modes: + 1. `existing` mode: it uses a workflow binary (and configuration) file that is already uploaded to Gist + 2. `new` mode: it compiles a new workflow binary and uploads it to Gist + + For the `new` mode to work, the `GITHUB_API_TOKEN` env var must be set to a token that has `gist:read` and `gist:write` permissions, but this permissions + are tied to account not to repository. Currently, we have no service account in the CI at all. And using a token that's tied to personal account of a developer + is not a good idea. So, for now, we are only allowing the `existing` mode in CI. + */ + require.True(t, testConfig.WorkflowConfig.UseExising, "only existing workflow can be used in CI as of now due to issues with generating a gist read:write token") // we use this special function to subsitute a placeholder env variable with the actual environment variable name // it is defined in .github/e2e-tests.yml as '{{ env.GITHUB_API_TOKEN }}' @@ -556,66 +388,118 @@ func validateInputsAndEnvVars(t *testing.T, testConfig *WorkflowTestConfig) { require.NotEmpty(t, testConfig.WorkflowConfig.ChainlinkCLI.FolderLocation, "folder_location must be set in the chainlink_cli config") } } + + // make sure the feed id is in the correct format + testConfig.WorkflowConfig.FeedID = strings.TrimPrefix(testConfig.WorkflowConfig.FeedID, "0x") } -func buildChainlinkDeploymentEnv(t *testing.T, sc *seth.Client) (*deployment.Environment, uint64) { - lgr := logger.TestLogger(t) +// copied from Bala's unmerged PR: https://github.com/smartcontractkit/chainlink/pull/15751 +// TODO: remove this once the PR is merged and import his function +func getNodeInfo(nodeOut *ns.Output, bootstrapNodeCount int) ([]devenv.NodeInfo, error) { + var nodeInfo []devenv.NodeInfo + for i := 1; i <= len(nodeOut.CLNodes); i++ { + p2pURL, err := url.Parse(nodeOut.CLNodes[i-1].Node.DockerP2PUrl) + if err != nil { + return nil, fmt.Errorf("failed to parse p2p url: %w", err) + } + if i <= bootstrapNodeCount { + nodeInfo = append(nodeInfo, devenv.NodeInfo{ + IsBootstrap: true, + Name: fmt.Sprintf("bootstrap-%d", i), + P2PPort: p2pURL.Port(), + CLConfig: nodeclient.ChainlinkConfig{ + URL: nodeOut.CLNodes[i-1].Node.HostURL, + Email: nodeOut.CLNodes[i-1].Node.APIAuthUser, + Password: nodeOut.CLNodes[i-1].Node.APIAuthPassword, + InternalIP: nodeOut.CLNodes[i-1].Node.InternalIP, + }, + }) + } else { + nodeInfo = append(nodeInfo, devenv.NodeInfo{ + IsBootstrap: false, + Name: fmt.Sprintf("node-%d", i), + P2PPort: p2pURL.Port(), + CLConfig: nodeclient.ChainlinkConfig{ + URL: nodeOut.CLNodes[i-1].Node.HostURL, + Email: nodeOut.CLNodes[i-1].Node.APIAuthUser, + Password: nodeOut.CLNodes[i-1].Node.APIAuthPassword, + InternalIP: nodeOut.CLNodes[i-1].Node.InternalIP, + }, + }) + } + } + return nodeInfo, nil +} - addressBook := deployment.NewMemoryAddressBook() - chainMap := make(map[uint64]deployment.Chain) - ctx := context.Background() +func buildChainlinkDeploymentEnv(t *testing.T, jdOutput *jd.Output, nodeOutput *ns.Output, bs *blockchain.Output, sc *seth.Client) (*deployment.Environment, *devenv.DON, uint64) { + lgr := logger.TestLogger(t) chainSelector, err := chainselectors.SelectorFromChainId(sc.Cfg.Network.ChainID) require.NoError(t, err, "failed to get chain selector for chain id %d", sc.Cfg.Network.ChainID) - chainMap[chainSelector] = deployment.Chain{ - Selector: chainSelector, - Client: sc.Client, - DeployerKey: sc.NewTXOpts(seth.WithNonce(nil)), // set nonce to nil, so that it will be fetched from the chain - Confirm: func(tx *geth_types.Transaction) (uint64, error) { - decoded, revertErr := sc.DecodeTx(tx) - if revertErr != nil { - return 0, revertErr - } - if decoded.Receipt == nil { - return 0, fmt.Errorf("no receipt found for transaction %s even though it wasn't reverted. This should not happen", tx.Hash().String()) - } - return decoded.Receipt.BlockNumber.Uint64(), nil + + nodeInfo, err := getNodeInfo(nodeOutput, 1) + require.NoError(t, err, "failed to get node info") + + jdConfig := devenv.JDConfig{ + GRPC: jdOutput.HostGRPCUrl, + WSRPC: jdOutput.DockerWSRPCUrl, + Creds: insecure.NewCredentials(), + NodeInfo: nodeInfo, + } + + require.GreaterOrEqual(t, len(bs.Nodes), 1, "expected at least one node in the blockchain output") + + devenvConfig := devenv.EnvironmentConfig{ + JDConfig: jdConfig, + Chains: []devenv.ChainConfig{ + { + ChainID: sc.Cfg.Network.ChainID, + ChainName: sc.Cfg.Network.Name, + ChainType: strings.ToUpper(bs.Family), + WSRPCs: []devenv.CribRPCs{{ + External: bs.Nodes[0].HostWSUrl, + Internal: bs.Nodes[0].DockerInternalWSUrl, + }}, + HTTPRPCs: []devenv.CribRPCs{{ + External: bs.Nodes[0].HostHTTPUrl, + Internal: bs.Nodes[0].DockerInternalHTTPUrl, + }}, + DeployerKey: sc.NewTXOpts(seth.WithNonce(nil)), // set nonce to nil, so that it will be fetched from the chain + }, }, } - return deployment.NewEnvironment("ctfV2", lgr, addressBook, chainMap, nil, nil, nil, func() context.Context { return ctx }, deployment.OCRSecrets{}), chainSelector + env, don, err := devenv.NewEnvironment(context.Background, lgr, devenvConfig) + require.NoError(t, err, "failed to create environment") + + return env, don, chainSelector } -func prepareCapabilitiesRegistry(t *testing.T, sc *seth.Client, allCaps []cr_wrapper.CapabilitiesRegistryCapability) (common.Address, [][32]byte) { - capRegAddr, tx, capabilitiesRegistryInstance, err := cr_wrapper.DeployCapabilitiesRegistry(sc.NewTXOpts(), sc.Client) - _, decodeErr := sc.Decode(tx, err) - require.NoError(t, decodeErr, "failed to deploy capabilities registry contract") +func deployKeystoneContracts(t *testing.T, testLogger zerolog.Logger, ctfEnv *deployment.Environment, chainSelector uint64) keystone_changeset.ContractSet { + // Deploy keystone forwarder contract + _ = deployKeystoneForwarder(t, testLogger, ctfEnv, chainSelector) - _, decodeErr = sc.Decode(capabilitiesRegistryInstance.AddCapabilities( - sc.NewTXOpts(), - allCaps, - )) - require.NoError(t, decodeErr, "failed to add capabilities to capabilities registry") - - hashedCapabilities := make([][32]byte, len(allCaps)) - for i, capability := range allCaps { - hashed, err := capabilitiesRegistryInstance.GetHashedCapabilityId( - sc.NewCallOpts(), - capability.LabelledName, - capability.Version, - ) - require.NoError(t, err, "failed to get hashed capability ID for %s", capability.LabelledName) - hashedCapabilities[i] = hashed - } + // Deploy OCR3 contract + _ = deployOCR3(t, testLogger, ctfEnv, chainSelector) - return capRegAddr, hashedCapabilities -} + // Deploy capabilities registry contract + _ = deployCapabilitiesRegistry(t, testLogger, ctfEnv, chainSelector) -func deployKeystoneForwarder(t *testing.T, testLogger zerolog.Logger, ctfEnv *deployment.Environment, chainSelector uint64) common.Address { - output, err := keystone_changeset.DeployForwarder(*ctfEnv, keystone_changeset.DeployForwarderRequest{ - ChainSelectors: []uint64{chainSelector}, + contractSetResponse, err := keystone_changeset.GetContractSets(nil, &keystone_changeset.GetContractSetsRequest{ + Chains: ctfEnv.Chains, + AddressBook: ctfEnv.ExistingAddresses, }) - require.NoError(t, err, "failed to deploy forwarder contract") + require.NoError(t, err, "failed to get contract sets") + + contractSet, ok := contractSetResponse.ContractSets[chainSelector] + require.True(t, ok, "failed to get contract set for chain %d", chainSelector) + + return contractSet +} + +func deployOCR3(t *testing.T, testLogger zerolog.Logger, ctfEnv *deployment.Environment, chainSelector uint64) common.Address { + output, err := keystone_changeset.DeployOCR3(*ctfEnv, chainSelector) + require.NoError(t, err, "failed to deploy OCR3 Capability contract") err = ctfEnv.ExistingAddresses.Merge(output.AddressBook) require.NoError(t, err, "failed to merge address book") @@ -625,9 +509,9 @@ func deployKeystoneForwarder(t *testing.T, testLogger zerolog.Logger, ctfEnv *de var forwarderAddress common.Address for addrStr, tv := range addresses { - if strings.Contains(tv.String(), "KeystoneForwarder") { + if strings.Contains(tv.String(), "OCR3Capability") { forwarderAddress = common.HexToAddress(addrStr) - testLogger.Info().Msgf("Deployed KeystoneForwarder contract at %s", forwarderAddress.Hex()) + testLogger.Info().Msgf("Deployed OCR3Capability contract at %s", forwarderAddress.Hex()) break } } @@ -635,47 +519,50 @@ func deployKeystoneForwarder(t *testing.T, testLogger zerolog.Logger, ctfEnv *de return forwarderAddress } -func configureKeystoneForwarder(t *testing.T, forwarderAddress common.Address, sc *seth.Client, nodesInfo []NodeInfo) { - forwarderInstance, err := forwarder.NewKeystoneForwarder(forwarderAddress, sc.Client) - require.NoError(t, err, "failed to create forwarder instance") +func deployCapabilitiesRegistry(t *testing.T, testLogger zerolog.Logger, ctfEnv *deployment.Environment, chainSelector uint64) common.Address { + output, err := keystone_changeset.DeployCapabilityRegistry(*ctfEnv, chainSelector) + require.NoError(t, err, "failed to deploy Capabilities Registry contract") + + err = ctfEnv.ExistingAddresses.Merge(output.AddressBook) + require.NoError(t, err, "failed to merge address book") - signers := make([]common.Address, len(nodesInfo)-1) + addresses, err := ctfEnv.ExistingAddresses.AddressesForChain(chainSelector) + require.NoError(t, err, "failed to get addresses for chain %d from the address book", chainSelector) - for i, node := range nodesInfo { - // skip the first node, as it's the bootstrap node - // it doesn't have any capabilities that are required by the workflow - if i == 0 { - continue + var forwarderAddress common.Address + for addrStr, tv := range addresses { + if strings.Contains(tv.String(), "CapabilitiesRegistry") { + forwarderAddress = common.HexToAddress(addrStr) + testLogger.Info().Msgf("Deployed Capabilities Registry contract at %s", forwarderAddress.Hex()) + break } - signers[i-1] = node.Signer } - _, err = sc.Decode(forwarderInstance.SetConfig( - sc.NewTXOpts(), - 1, // donID - 1, // configVersion -- wonder what it does - 1, // maximum number of faulty nodes - signers)) - require.NoError(t, err, "failed to set config for forwarder") + return forwarderAddress } -func configureOCR3Capability(t *testing.T, ocr3CapabilityAddress common.Address, sc *seth.Client, nodeInfo []NodeInfo) { - workflowNodesetInfo := nodeInfo[1:] +func deployKeystoneForwarder(t *testing.T, testLogger zerolog.Logger, ctfEnv *deployment.Environment, chainSelector uint64) common.Address { + output, err := keystone_changeset.DeployForwarder(*ctfEnv, keystone_changeset.DeployForwarderRequest{ + ChainSelectors: []uint64{chainSelector}, + }) + require.NoError(t, err, "failed to deploy forwarder contract") - ocr3CapabilityContract, err := ocr3_capability.NewOCR3Capability(ocr3CapabilityAddress, sc.Client) - require.NoError(t, err, "failed to create OCR3 capability contract instance") + err = ctfEnv.ExistingAddresses.Merge(output.AddressBook) + require.NoError(t, err, "failed to merge address book") - ocr3Config := generateOCR3Config(t, workflowNodesetInfo) - _, decodeErr := sc.Decode(ocr3CapabilityContract.SetConfig( - sc.NewTXOpts(), - ocr3Config.Signers, - ocr3Config.Transmitters, - ocr3Config.F, - ocr3Config.OnchainConfig, - ocr3Config.OffchainConfigVersion, - ocr3Config.OffchainConfig, - )) - require.NoError(t, decodeErr, "failed to set OCR3 configuration") + addresses, err := ctfEnv.ExistingAddresses.AddressesForChain(chainSelector) + require.NoError(t, err, "failed to get addresses for chain %d from the address book", chainSelector) + + var forwarderAddress common.Address + for addrStr, tv := range addresses { + if strings.Contains(tv.String(), "KeystoneForwarder") { + forwarderAddress = common.HexToAddress(addrStr) + testLogger.Info().Msgf("Deployed KeystoneForwarder contract at %s", forwarderAddress.Hex()) + break + } + } + + return forwarderAddress } func prepareWorkflowRegistry(t *testing.T, testLogger zerolog.Logger, ctfEnv *deployment.Environment, chainSelector uint64, sc *seth.Client, donID uint32) common.Address { @@ -772,18 +659,6 @@ func prepareFeedsConsumer(t *testing.T, testLogger zerolog.Logger, ctfEnv *deplo return feedsConsumerAddress } -func deployOCR3Capability(t *testing.T, testLogger zerolog.Logger, sc *seth.Client) common.Address { - ocr3CapabilityAddress, tx, _, err := ocr3_capability.DeployOCR3Capability( - sc.NewTXOpts(), - sc.Client, - ) - _, decodeErr := sc.Decode(tx, err) - require.NoError(t, decodeErr, "failed to deploy OCR Capability contract") - - testLogger.Info().Msgf("Deployed OCR3 Capability contract at %s", ocr3CapabilityAddress.Hex()) - - return ocr3CapabilityAddress -} func registerWorkflowDirectly(t *testing.T, in *WorkflowTestConfig, sc *seth.Client, workflowRegistryAddr common.Address, donID uint32, workflowName string) { require.NotEmpty(t, in.WorkflowConfig.Existing.BinaryURL) workFlowData, err := downloadAndDecode(in.WorkflowConfig.Existing.BinaryURL) @@ -808,14 +683,23 @@ func registerWorkflowDirectly(t *testing.T, in *WorkflowTestConfig, sc *seth.Cli } //revive:disable // ignore confusing-results -func compileWorkflowWithChainlinkCli(t *testing.T, in *WorkflowTestConfig, feedsConsumerAddress common.Address, settingsFile *os.File) (string, string) { - feedID := "0x018BFE88407000400000000000000000" - +func compileWorkflowWithChainlinkCli(t *testing.T, in *WorkflowTestConfig, feedsConsumerAddress common.Address, feedID string, settingsFile *os.File) (string, string) { configFile, err := os.CreateTemp("", "config.json") require.NoError(t, err, "failed to create workflow config file") + cleanFeedId := strings.TrimPrefix(feedID, "0x") + feedLength := len(cleanFeedId) + + require.GreaterOrEqual(t, feedLength, 32, "feed ID must be at least 32 characters long") + + if feedLength > 32 { + cleanFeedId = cleanFeedId[:32] + } + + feedIDToUse := "0x" + cleanFeedId + workflowConfig := PoRWorkflowConfig{ - FeedID: feedID, + FeedID: feedIDToUse, URL: "https://api.real-time-reserves.verinumus.io/v1/chainlink/proof-of-reserves/TrueUSD", ConsumerAddress: feedsConsumerAddress.Hex(), } @@ -836,10 +720,10 @@ func compileWorkflowWithChainlinkCli(t *testing.T, in *WorkflowTestConfig, feeds require.NoError(t, err, "failed to start compile command") err = compileCmd.Wait() - require.NoError(t, err, "failed to wait for compile command") - fmt.Println("Compile output:\n", outputBuffer.String()) + require.NoError(t, err, "failed to wait for compile command") + re := regexp.MustCompile(`Gist URL=([^\s]+)`) matches := re.FindAllStringSubmatch(outputBuffer.String(), -1) require.Len(t, matches, 2, "failed to find 2 gist URLs in compile output") @@ -929,7 +813,7 @@ func registerWorkflow(t *testing.T, in *WorkflowTestConfig, sc *seth.Client, cap // compile and upload the workflow, if we are not using an existing one if !in.WorkflowConfig.UseExising { - workflowGistURL, workflowConfigURL = compileWorkflowWithChainlinkCli(t, in, feedsConsumerAddress, settingsFile) + workflowGistURL, workflowConfigURL = compileWorkflowWithChainlinkCli(t, in, feedsConsumerAddress, in.WorkflowConfig.FeedID, settingsFile) } else { workflowGistURL = in.WorkflowConfig.Existing.BinaryURL workflowConfigURL = in.WorkflowConfig.Existing.ConfigURL @@ -943,7 +827,7 @@ func registerWorkflow(t *testing.T, in *WorkflowTestConfig, sc *seth.Client, cap require.NoError(t, err, "failed to register workflow using chainlink-cli") } -func starAndFundNodes(t *testing.T, in *WorkflowTestConfig, bc *blockchain.Output, sc *seth.Client) (*ns.Output, []NodeInfo) { +func startNodes(t *testing.T, in *WorkflowTestConfig, bc *blockchain.Output) *ns.Output { // Hack for CI that allows us to dynamically set the chainlink image and version // CTFv2 currently doesn't support dynamic image and version setting if os.Getenv("IS_CI") == "true" { @@ -958,27 +842,25 @@ func starAndFundNodes(t *testing.T, in *WorkflowTestConfig, bc *blockchain.Outpu nodeset, err := ns.NewSharedDBNodeSet(in.NodeSet, bc) require.NoError(t, err, "failed to deploy node set") - nodeClients, err := clclient.New(nodeset.CLNodes) - require.NoError(t, err, "failed to create chainlink clients") - - nodesInfo := getNodesInfo(t, nodeClients) + return nodeset +} - // Fund all nodes - for _, nodeInfo := range nodesInfo { +func fundNodes(t *testing.T, don *devenv.DON, sc *seth.Client) { + for _, node := range don.Nodes { _, err := actions.SendFunds(zerolog.Logger{}, sc, actions.FundsToSendPayload{ - ToAddress: common.HexToAddress(nodeInfo.TransmitterAddress), + ToAddress: common.HexToAddress(node.AccountAddr[sc.Cfg.Network.ChainID]), Amount: big.NewInt(5000000000000000000), PrivateKey: sc.MustGetRootPrivateKey(), }) require.NoError(t, err) } - - return nodeset, nodesInfo } -func configureNodes(t *testing.T, nodesInfo []NodeInfo, in *WorkflowTestConfig, bc *blockchain.Output, capRegAddr common.Address, workflowRegistryAddr common.Address, forwarderAddress common.Address) (*ns.Output, []*clclient.ChainlinkClient) { - bootstrapNodeInfo := nodesInfo[0] - workflowNodesetInfo := nodesInfo[1:] +func configureNodes(t *testing.T, don *devenv.DON, in *WorkflowTestConfig, bc *blockchain.Output, capRegAddr, workflowRegistryAddr, forwarderAddress common.Address) (*ns.Output, []*clclient.ChainlinkClient) { + workflowNodeSet := don.Nodes[1:] + + bootstrapNodePeerId, err := nodeToP2PID(don.Nodes[0], keyExtractingTransformFn) + require.NoError(t, err, "failed to get bootstrap node peer ID") // configure the bootstrap node in.NodeSet.NodeSpecs[0].Node.TestConfigOverrides = fmt.Sprintf(` @@ -1009,16 +891,20 @@ func configureNodes(t *testing.T, nodesInfo []NodeInfo, in *WorkflowTestConfig, WSURL = '%s' HTTPURL = '%s' `, - bootstrapNodeInfo.PeerID, - bootstrapNodeInfo.PeerID, + bootstrapNodePeerId, + bootstrapNodePeerId, bc.ChainID, bc.Nodes[0].DockerInternalWSUrl, bc.Nodes[0].DockerInternalHTTPUrl, ) + chainIDInt, err := strconv.Atoi(bc.ChainID) + require.NoError(t, err, "failed to convert chain ID to int") + chainIDUint64 := mustSafeUint64(int64(chainIDInt)) + // configure worker nodes with p2p, peering capabilitity (for DON-2-DON communication), // capability (external) registry, workflow registry and gateway connector (required for reading from workflow registry and for external communication) - for i := range workflowNodesetInfo { + for i := range workflowNodeSet { in.NodeSet.NodeSpecs[i+1].Node.TestConfigOverrides = fmt.Sprintf(` [Feature] LogPoller = true @@ -1065,7 +951,7 @@ func configureNodes(t *testing.T, nodesInfo []NodeInfo, in *WorkflowTestConfig, ChainID = "%s" [Capabilities.GatewayConnector] - DonID = "1" + DonID = "%s" ChainIDForNodeKey = "%s" NodeAddress = '%s' @@ -1073,19 +959,20 @@ func configureNodes(t *testing.T, nodesInfo []NodeInfo, in *WorkflowTestConfig, Id = "por_gateway" URL = "%s" `, - bootstrapNodeInfo.PeerID, - bootstrapNodeInfo.PeerID, + bootstrapNodePeerId, + bootstrapNodePeerId, bc.ChainID, bc.Nodes[0].DockerInternalWSUrl, bc.Nodes[0].DockerInternalHTTPUrl, - workflowNodesetInfo[i].TransmitterAddress, + workflowNodeSet[i].AccountAddr[chainIDUint64], forwarderAddress.Hex(), capRegAddr, bc.ChainID, workflowRegistryAddr.Hex(), bc.ChainID, + strconv.FormatUint(uint64(in.WorkflowConfig.DonID), 10), bc.ChainID, - workflowNodesetInfo[i].TransmitterAddress, + workflowNodeSet[i].AccountAddr[chainIDUint64], "ws://node0:5003/node", // bootstrap node exposes gateway port on 5003 ) } @@ -1101,9 +988,26 @@ func configureNodes(t *testing.T, nodesInfo []NodeInfo, in *WorkflowTestConfig, return nodeset, nodeClients } -func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, nodesInfo []NodeInfo, bc *blockchain.Output, ocr3CapabilityAddress common.Address) { - bootstrapNodeInfo := nodesInfo[0] - workflowNodesetInfo := nodesInfo[1:] +func mustSafeUint64(input int64) uint64 { + if input < 0 { + panic(fmt.Errorf("int64 %d is below uint64 min value", input)) + } + return uint64(input) +} + +func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don *devenv.DON, bc *blockchain.Output, keystoneContractSet keystone_changeset.ContractSet, donID uint32) { + // if there's only one OCR3 contract in the set, we can use `nil` as the address to get its instance + ocr3Contract, err := keystoneContractSet.GetOCR3Contract(nil) + require.NoError(t, err, "failed to get OCR3 contract address") + + ocr3CapabilityAddress := ocr3Contract.Address().Hex() + + bootstrapNodePeerId, err := nodeToP2PID(don.Nodes[0], keyExtractingTransformFn) + require.NoError(t, err, "failed to get bootstrap node peer ID") + + chainIDInt, err := strconv.Atoi(bc.ChainID) + require.NoError(t, err, "failed to convert chain ID to int") + chainIDUint64 := mustSafeUint64(int64(chainIDInt)) // Create gateway and bootstrap (ocr3) jobs for the bootstrap node bootstrapNode := nodeClients[0] @@ -1124,7 +1028,10 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, nodes [relayConfig] chainID = %s providerType = "ocr3-capability" - `, ocr3CapabilityAddress, bc.ChainID) + `, + ocr3CapabilityAddress, + bc.ChainID, + ) r, _, bootErr := bootstrapNode.CreateJobRaw(bootstrapJobSpec) assert.NoError(t, bootErr, "failed to create bootstrap job for the bootstrap node") assert.Empty(t, r.Errors, "failed to create bootstrap job for the bootstrap node") @@ -1132,7 +1039,7 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, nodes gatewayJobSpec := fmt.Sprintf(` type = "gateway" schemaVersion = 1 - name = "PoR Gateway" + name = "Gateway" forwardingAllowed = false [gatewayConfig.ConnectionManagerConfig] @@ -1142,9 +1049,10 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, nodes HeartbeatIntervalSec = 20 [[gatewayConfig.Dons]] - DonId = "1" + DonId = "%s" F = 1 HandlerName = "web-api-capabilities" + [gatewayConfig.Dons.HandlerConfig] MaxAllowedMessageAgeSec = 1_000 @@ -1188,11 +1096,12 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, nodes [gatewayConfig.HTTPClientConfig] MaxResponseBytes = 100_000_000 `, + strconv.FormatUint(uint64(donID), 10), // ETH keys of the workflow nodes - workflowNodesetInfo[0].TransmitterAddress, - workflowNodesetInfo[1].TransmitterAddress, - workflowNodesetInfo[2].TransmitterAddress, - workflowNodesetInfo[3].TransmitterAddress, + don.Nodes[1].AccountAddr[chainIDUint64], + don.Nodes[2].AccountAddr[chainIDUint64], + don.Nodes[3].AccountAddr[chainIDUint64], + don.Nodes[4].AccountAddr[chainIDUint64], ) r, _, gatewayErr := bootstrapNode.CreateJobRaw(gatewayJobSpec) @@ -1219,7 +1128,9 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, nodes forwardingAllowed = false command = "/home/capabilities/%s" config = "" - `, cronCapabilityAssetFile) + `, + cronCapabilityAssetFile, + ) response, _, errCron := nodeClient.CreateJobRaw(cronJobSpec) assert.NoError(t, errCron, "failed to create cron job") @@ -1274,12 +1185,12 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, nodes evm = "%s" `, ocr3CapabilityAddress, - nodesInfo[i].OcrKeyBundleID, - bootstrapNodeInfo.PeerID, + don.Nodes[i].Ocr2KeyBundleID, + bootstrapNodePeerId, "node0:5001", - nodesInfo[i].TransmitterAddress, + don.Nodes[i].AccountAddr[chainIDUint64], bc.ChainID, - nodesInfo[i].OcrKeyBundleID, + don.Nodes[i].Ocr2KeyBundleID, ) fmt.Println("consensusJobSpec", consensusJobSpec) response, _, errCons := nodeClient.CreateJobRaw(consensusJobSpec) @@ -1290,73 +1201,142 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, nodes wg.Wait() } -func registerDONAndCapabilities(t *testing.T, capRegAddr common.Address, hashedCapabilities [][32]byte, nodesInfo []NodeInfo, sc *seth.Client) { - // Register node operators, nodes and DON in the Capabilities registry - nopsToAdd := make([]cr_wrapper.CapabilitiesRegistryNodeOperator, len(nodesInfo)-1) - nodesToAdd := make([]cr_wrapper.CapabilitiesRegistryNodeParams, len(nodesInfo)-1) - donNodes := make([][32]byte, len(nodesInfo)-1) +func noOpTransformFn(value string) string { + return value +} + +func keyExtractingTransformFn(value string) string { + parts := strings.Split(value, "_") + if len(parts) > 1 { + return parts[len(parts)-1] + } + return value +} + +func nodeToP2PID(node devenv.Node, transformFn func(string) string) (string, error) { + for _, label := range node.Labels() { + if label.Key == devenv.NodeLabelP2PIDType { + if label.Value == nil { + return "", fmt.Errorf("p2p label value is nil for node %s", node.Name) + } + return transformFn(*label.Value), nil + } + } + + return "", fmt.Errorf("p2p label not found for node %s", node.Name) +} + +func configureWorkflowDON(t *testing.T, ctfEnv *deployment.Environment, don *devenv.DON, chainSelector uint64) { + kcrAllCaps := []keystone_changeset.DONCapabilityWithConfig{ + { + Capability: kcr.CapabilitiesRegistryCapability{ + LabelledName: "offchain_reporting", + Version: "1.0.0", + CapabilityType: 2, // CONSENSUS + ResponseType: 0, // REPORT + }, + Config: &capabilitiespb.CapabilityConfig{}, + }, + { + Capability: kcr.CapabilitiesRegistryCapability{ + LabelledName: "write_geth-testnet", + Version: "1.0.0", + CapabilityType: 3, // TARGET + ResponseType: 1, // OBSERVATION_IDENTICAL + }, + Config: &capabilitiespb.CapabilityConfig{}, + }, + { + Capability: kcr.CapabilitiesRegistryCapability{ + LabelledName: "cron-trigger", + Version: "1.0.0", + CapabilityType: uint8(0), // trigger + }, + Config: &capabilitiespb.CapabilityConfig{}, + }, + { + Capability: kcr.CapabilitiesRegistryCapability{ + LabelledName: "custom-compute", + Version: "1.0.0", + CapabilityType: uint8(1), // action + }, + Config: &capabilitiespb.CapabilityConfig{}, + }, + } - for i, node := range nodesInfo { - // skip the first node, as it's the bootstrap node - // it doesn't have any capabilities that are required by the workflow + peerIds := make([]string, len(don.Nodes)-1) + for i, node := range don.Nodes { if i == 0 { continue } - nopsToAdd[i-1] = cr_wrapper.CapabilitiesRegistryNodeOperator{ - Admin: common.HexToAddress(node.TransmitterAddress), - Name: fmt.Sprintf("NOP %d", i), - } - var peerID ragetypes.PeerID - err := peerID.UnmarshalText([]byte(node.PeerID)) - require.NoError(t, err, "failed to unmarshal peer ID") + p2pId, err := nodeToP2PID(node, noOpTransformFn) + require.NoError(t, err, "failed to get p2p id for node %s", node.Name) - nodesToAdd[i-1] = cr_wrapper.CapabilitiesRegistryNodeParams{ - NodeOperatorId: uint32(i), //nolint:gosec // disable G115 - Signer: common.BytesToHash(node.Signer.Bytes()), - P2pId: peerID, - EncryptionPublicKey: [32]byte{1, 2, 3, 4, 5}, - HashedCapabilityIds: hashedCapabilities, - } + peerIds[i-1] = p2pId + } - donNodes[i-1] = peerID + nop := keystone_changeset.NOP{ + Name: "NOP 1", + Nodes: peerIds, } - capabilitiesRegistryInstance, err := cr_wrapper.NewCapabilitiesRegistry(capRegAddr, sc.Client) - require.NoError(t, err, "failed to create capabilities registry instance") + donName := "keystone-don" + donCap := keystone_changeset.DonCapabilities{ + Name: donName, + F: 1, + Nops: []keystone_changeset.NOP{nop}, + Capabilities: kcrAllCaps, + } - // Add NOPs to capabilities registry - _, decodeErr := sc.Decode(capabilitiesRegistryInstance.AddNodeOperators( - sc.NewTXOpts(), - nopsToAdd, - )) - require.NoError(t, decodeErr, "failed to add NOPs to capabilities registry") + transmissionSchedule := make([]int, len(don.Nodes)-1) + for i := range transmissionSchedule { + transmissionSchedule[i] = i + 1 + } - // Add nodes to capabilities registry - _, decodeErr = sc.Decode(capabilitiesRegistryInstance.AddNodes( - sc.NewTXOpts(), - nodesToAdd, - )) - require.NoError(t, decodeErr, "failed to add nodes to capabilities registry") + // values supplied by Alexandr Yepishev as the expected values for OCR3 config + oracleConfig := keystone_changeset.OracleConfig{ + DeltaProgressMillis: 5000, + DeltaResendMillis: 5000, + DeltaInitialMillis: 5000, + DeltaRoundMillis: 2000, + DeltaGraceMillis: 500, + DeltaCertifiedCommitRequestMillis: 1000, + DeltaStageMillis: 30000, + MaxRoundsPerEpoch: 10, + TransmissionSchedule: transmissionSchedule, + MaxDurationQueryMillis: 1000, + MaxDurationObservationMillis: 1000, + MaxDurationAcceptMillis: 1000, + MaxDurationTransmitMillis: 1000, + MaxFaultyOracles: 1, + MaxQueryLengthBytes: 1000000, + MaxObservationLengthBytes: 1000000, + MaxReportLengthBytes: 1000000, + MaxRequestBatchSize: 1000, + UniqueReports: true, + } - capRegConfig := make([]cr_wrapper.CapabilitiesRegistryCapabilityConfiguration, len(hashedCapabilities)) - for i, hashed := range hashedCapabilities { - capRegConfig[i] = cr_wrapper.CapabilitiesRegistryCapabilityConfiguration{ - CapabilityId: hashed, - Config: []byte(""), - } + cfg := keystone_changeset.InitialContractsCfg{ + RegistryChainSel: chainSelector, + Dons: []keystone_changeset.DonCapabilities{donCap}, + OCR3Config: &oracleConfig, } - // Add nodeset to capabilities registry - _, decodeErr = sc.Decode(capabilitiesRegistryInstance.AddDON( - sc.NewTXOpts(), - donNodes, - capRegConfig, - true, // is public - true, // accepts workflows - uint8(1), // max number of malicious nodes - )) - require.NoError(t, decodeErr, "failed to add DON to capabilities registry") + _, err := keystone_changeset.ConfigureInitialContractsChangeset(*ctfEnv, cfg) + require.NoError(t, err, "failed to configure initial contracts") +} + +func startJobDistributor(t *testing.T, in *WorkflowTestConfig) *jd.Output { + if os.Getenv("IS_CI") == "true" { + jdImage := ctfconfig.MustReadEnvVar_String(e2eJobDistributorImageEnvVarName) + jdVersion := os.Getenv(e2eJobDistributorVersionEnvVarName) + in.JD.Image = fmt.Sprintf("%s:%s", jdImage, jdVersion) + } + jdOutput, err := jd.NewJD(in.JD) + require.NoError(t, err, "failed to create new job distributor") + + return jdOutput } func getLogFileHandles(t *testing.T, l zerolog.Logger, ns *ns.Output) ([]*os.File, error) { @@ -1603,7 +1583,7 @@ func checkIfAtLeastOneReportWasSent(logFiles []*os.File, workflowNodeCount int) } func logTestInfo(l zerolog.Logger, feedId, workflowName, feedConsumerAddr, forwarderAddr string) { - l.Info().Msg("Test configuration:") + l.Info().Msg("------ Test configuration:") l.Info().Msgf("Feed ID: %s", feedId) l.Info().Msgf("Workflow name: %s", workflowName) l.Info().Msgf("FeedConsumer address: %s", feedConsumerAddr) @@ -1615,27 +1595,20 @@ func logTestInfo(l zerolog.Logger, feedId, workflowName, feedConsumerAddr, forwa Do not use this test as a template for your tests. It's hacky, since we were working under time pressure. We will soon refactor it follow best practices and a golden example. Apart from its structure what is currently missing is: -- using `chainlink/deployment` to deploy and configure all the contracts - using Job Distribution to create jobs for the nodes -- using only `chainlink-cli` to register the workflow +- using only `chainlink-cli` to register the workflow (it's there, but doesn't work in CI due to insufficient Github token permissions) - using a mock service to provide the feed data */ func TestKeystoneWithOCR3Workflow(t *testing.T) { testLogger := framework.L - // Define test configuration - donID := uint32(1) - workflowName := "abcdefgasd" - feedID := "018bfe8840700040000000000000000000000000000000000000000000000000" // without 0x prefix! - feedBytes := common.HexToHash(feedID) - // we need to use double-pointers, so that what's captured in the cleanup function is a pointer, not the actual object, // which is only set later in the test, after the cleanup function is defined var nodes **ns.Output var wsRPCURL *string // clean up is LIFO, so we need to make sure we execute the debug report transmission after logs are written down - // by function added to clean up by framework.Load() method. + // by function added to clean up by framework.Load() method t.Cleanup(func() { if t.Failed() { if nodes == nil { @@ -1663,78 +1636,46 @@ func TestKeystoneWithOCR3Workflow(t *testing.T) { Build() require.NoError(t, err, "failed to create seth client") + // Start job distributor + jdOutput := startJobDistributor(t, in) + + // Deploy the DON + nodeOutput := startNodes(t, in, bc) + // Prepare the chainlink/deployment environment - ctfEnv, chainSelector := buildChainlinkDeploymentEnv(t, sc) + ctfEnv, don, chainSelector := buildChainlinkDeploymentEnv(t, jdOutput, nodeOutput, bc, sc) - // Define required capabilities - // These need to match the capabilities that are required by the workflow, - // which in our case is a Proof-of-Reserves workflow - allCaps := []cr_wrapper.CapabilitiesRegistryCapability{ - { - LabelledName: "offchain_reporting", - Version: "1.0.0", - CapabilityType: 2, // CONSENSUS - ResponseType: 0, // REPORT - }, - { - LabelledName: "write_geth-testnet", - Version: "1.0.0", - CapabilityType: 3, // TARGET - ResponseType: 1, // OBSERVATION_IDENTICAL - }, - { - LabelledName: "cron-trigger", - Version: "1.0.0", - CapabilityType: uint8(0), // trigger - }, - { - LabelledName: "custom-compute", - Version: "1.0.0", - CapabilityType: uint8(1), // action - }, - } - capRegAddr, hashedCapabilities := prepareCapabilitiesRegistry(t, sc, allCaps) + // Fund the nodes + fundNodes(t, don, sc) - // Deploy keystone forwarder contract - forwarderAddress := deployKeystoneForwarder(t, testLogger, ctfEnv, chainSelector) + // Deploy keystone contracts (forwarder, capability registry, ocr3 capability) + keystoneContractSet := deployKeystoneContracts(t, testLogger, ctfEnv, chainSelector) // Deploy and pre-configure workflow registry contract - workflowRegistryAddr := prepareWorkflowRegistry(t, testLogger, ctfEnv, chainSelector, sc, donID) + workflowRegistryAddr := prepareWorkflowRegistry(t, testLogger, ctfEnv, chainSelector, sc, in.WorkflowConfig.DonID) // Deploy and configure Keystone Feeds Consumer contract - feedsConsumerAddress := prepareFeedsConsumer(t, testLogger, ctfEnv, chainSelector, sc, forwarderAddress, workflowName) + feedsConsumerAddress := prepareFeedsConsumer(t, testLogger, ctfEnv, chainSelector, sc, keystoneContractSet.Forwarder.Address(), in.WorkflowConfig.WorkflowName) // Register the workflow (either via chainlink-cli or by calling the workflow registry directly) - registerWorkflow(t, in, sc, capRegAddr, workflowRegistryAddr, feedsConsumerAddress, donID, chainSelector, workflowName, pkey, bc.Nodes[0].HostHTTPUrl) + registerWorkflow(t, in, sc, keystoneContractSet.CapabilitiesRegistry.Address(), workflowRegistryAddr, feedsConsumerAddress, in.WorkflowConfig.DonID, chainSelector, in.WorkflowConfig.WorkflowName, pkey, bc.Nodes[0].HostHTTPUrl) - // Log basic information that might help debugging + // Create OCR3 and capability jobs for each node without JD + ns, nodeClients := configureNodes(t, don, in, bc, keystoneContractSet.CapabilitiesRegistry.Address(), workflowRegistryAddr, keystoneContractSet.Forwarder.Address()) + createNodeJobs(t, nodeClients, don, bc, keystoneContractSet, in.WorkflowConfig.DonID) + + // Log extra information that might help debugging t.Cleanup(func() { if t.Failed() { - logTestInfo(testLogger, feedID, workflowName, feedsConsumerAddress.Hex(), forwarderAddress.Hex()) + logTestInfo(testLogger, in.WorkflowConfig.FeedID, in.WorkflowConfig.WorkflowName, feedsConsumerAddress.Hex(), keystoneContractSet.Forwarder.Address().Hex()) } }) - // Deploy and fund the DON; create OCR3, Gateway and capability-related jobs - ns, nodesInfo := starAndFundNodes(t, in, bc, sc) - _, nodeClients := configureNodes(t, nodesInfo, in, bc, capRegAddr, workflowRegistryAddr, forwarderAddress) - // set variables that are needed for the cleanup function, which debugs report transmissions nodes = &ns wsRPCURL = &bc.Nodes[0].HostWSUrl - // Deploy OCR3 Capability contract - ocr3CapabilityAddress := deployOCR3Capability(t, testLogger, sc) - - // Create OCR3 and capability jobs for each node - createNodeJobs(t, nodeClients, nodesInfo, bc, ocr3CapabilityAddress) - - // Register DON and capabilities - registerDONAndCapabilities(t, capRegAddr, hashedCapabilities, nodesInfo, sc) - - // configure Keystone Forwarder contract - configureKeystoneForwarder(t, forwarderAddress, sc, nodesInfo) - - // CRUCIAL: Set OCR3 configuration AFTER all the OCR3 jobs are created + // CAUTION: It is crucial to configure OCR3 jobs on nodes before configuring the workflow contracts. // Wait for OCR listeners to be ready before setting the configuration. // If the ConfigSet event is missed, OCR protocol will not start. // TODO make it fluent! @@ -1742,8 +1683,8 @@ func TestKeystoneWithOCR3Workflow(t *testing.T) { time.Sleep(30 * time.Second) testLogger.Info().Msg("Proceeding to set OCR3 configuration.") - // Configure OCR3 capability contract - configureOCR3Capability(t, ocr3CapabilityAddress, sc, nodesInfo) + // Configure the workflow DON and contracts + configureWorkflowDON(t, ctfEnv, don, chainSelector) // It can take a while before the first report is produced, particularly on CI. timeout := 10 * time.Minute @@ -1753,7 +1694,10 @@ func TestKeystoneWithOCR3Workflow(t *testing.T) { feedsConsumerInstance, err := feeds_consumer.NewKeystoneFeedsConsumer(feedsConsumerAddress, sc.Client) require.NoError(t, err, "failed to create feeds consumer instance") + testLogger.Info().Msg("Waiting for feed to update...") startTime := time.Now() + feedBytes := common.HexToHash(in.WorkflowConfig.FeedID) + for { select { case <-ctx.Done(): From 71ffdf3c19ce0c6c841db6c19cb204a2230e3c60 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 30 Jan 2025 10:43:46 -0600 Subject: [PATCH 13/43] bump chainlink-cosmos (#16145) --- core/scripts/go.mod | 4 ++-- core/scripts/go.sum | 8 ++++---- deployment/go.mod | 4 ++-- deployment/go.sum | 8 ++++---- go.md | 6 ++---- go.mod | 4 ++-- go.sum | 8 ++++---- integration-tests/go.mod | 4 ++-- integration-tests/go.sum | 8 ++++---- integration-tests/load/go.mod | 4 ++-- integration-tests/load/go.sum | 8 ++++---- 11 files changed, 32 insertions(+), 34 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index f55202b4aea..56abdb380c0 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -317,9 +317,9 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.37 // indirect github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect - github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index fd653a96662..ed18faef765 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1335,14 +1335,14 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250121195549-294ec6a40b92 h1:lJi0dWfgNJl4Um5KzeZZPVBi//CPDfzzeVmv4Z2OGNY= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= diff --git a/deployment/go.mod b/deployment/go.mod index f6797ca8dcb..128923e1cf8 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -417,10 +417,10 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v0.0.0-20250123084029-58cce9b32112 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20250117224137-afdcdd75070d // indirect diff --git a/deployment/go.sum b/deployment/go.sum index 7c5ac0ab32b..d89341fea89 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1400,14 +1400,14 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250121195549-294ec6a40b92 h1:lJi0dWfgNJl4Um5KzeZZPVBi//CPDfzzeVmv4Z2OGNY= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= diff --git a/go.md b/go.md index 5dbd12c6b04..0fd34c923e1 100644 --- a/go.md +++ b/go.md @@ -31,7 +31,7 @@ flowchart LR chainlink-common --> grpc-proxy chainlink-common --> libocr click chainlink-common href "https://github.com/smartcontractkit/chainlink-common" - chainlink-cosmos --> chainlink-common + chainlink-cosmos --> chainlink-framework/chains click chainlink-cosmos href "https://github.com/smartcontractkit/chainlink-cosmos" chainlink-data-streams --> chainlink-common click chainlink-data-streams href "https://github.com/smartcontractkit/chainlink-data-streams" @@ -54,7 +54,6 @@ flowchart LR chainlink/v2 --> chainlink-cosmos chainlink/v2 --> chainlink-data-streams chainlink/v2 --> chainlink-feeds - chainlink/v2 --> chainlink-framework/chains chainlink/v2 --> chainlink-protos/orchestrator chainlink/v2 --> chainlink-protos/svr chainlink/v2 --> chainlink-solana @@ -130,7 +129,7 @@ flowchart LR chainlink-common --> grpc-proxy chainlink-common --> libocr click chainlink-common href "https://github.com/smartcontractkit/chainlink-common" - chainlink-cosmos --> chainlink-common + chainlink-cosmos --> chainlink-framework/chains click chainlink-cosmos href "https://github.com/smartcontractkit/chainlink-cosmos" chainlink-data-streams --> chainlink-common click chainlink-data-streams href "https://github.com/smartcontractkit/chainlink-data-streams" @@ -182,7 +181,6 @@ flowchart LR chainlink/v2 --> chainlink-cosmos chainlink/v2 --> chainlink-data-streams chainlink/v2 --> chainlink-feeds - chainlink/v2 --> chainlink-framework/chains chainlink/v2 --> chainlink-protos/orchestrator chainlink/v2 --> chainlink-protos/svr chainlink/v2 --> chainlink-solana diff --git a/go.mod b/go.mod index 11e8a3b8624..27cfc00056a 100644 --- a/go.mod +++ b/go.mod @@ -80,10 +80,10 @@ require ( github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d - github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 + github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 github.com/smartcontractkit/chainlink-feeds v0.1.1 - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92 + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20250121222331-a7010b4b8ce5 diff --git a/go.sum b/go.sum index d1e88d5d0c2..36d35039fa4 100644 --- a/go.sum +++ b/go.sum @@ -1158,14 +1158,14 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250121195549-294ec6a40b92 h1:lJi0dWfgNJl4Um5KzeZZPVBi//CPDfzzeVmv4Z2OGNY= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 h1:ZBat8EBvE2LpSQR9U1gEbRV6PfAkiFdINmQ8nVnXIAQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index f1c4123ccfa..7461f115b71 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -436,10 +436,10 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect - github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v0.0.0-20250123084029-58cce9b32112 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index a18c8e51e47..73fc2ab2ff9 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1428,14 +1428,14 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250121195549-294ec6a40b92 h1:lJi0dWfgNJl4Um5KzeZZPVBi//CPDfzzeVmv4Z2OGNY= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 768489287b8..ca671e62932 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -420,10 +420,10 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect - github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index cfed477edfa..febcadfabd0 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1415,14 +1415,14 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4 h1:w7w42ml8MOxdoyAZ9+og0342UkiH3deRM1V0Pj5JR5g= -github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250121210000-2a9675d7a1b4/go.mod h1:wtdAmAUMooLavbrTA7PgHg40lyDlKesxI/RR+5Xcz18= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= +github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250121195549-294ec6a40b92 h1:lJi0dWfgNJl4Um5KzeZZPVBi//CPDfzzeVmv4Z2OGNY= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250121195549-294ec6a40b92/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= From f2783f8ace87db2c3362a417f28e45d14285e643 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Thu, 30 Jan 2025 17:54:08 +0100 Subject: [PATCH 14/43] Bumping sampling intervals (#16114) --- ccip/config/evm/fallback.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ccip/config/evm/fallback.toml b/ccip/config/evm/fallback.toml index 86ec56dd0b7..c5d77c7a884 100644 --- a/ccip/config/evm/fallback.toml +++ b/ccip/config/evm/fallback.toml @@ -67,7 +67,7 @@ CacheTimeout = '10s' [HeadTracker] HistoryDepth = 100 MaxBufferSize = 3 -SamplingInterval = '1s' +SamplingInterval = '5s' FinalityTagBypass = true MaxAllowedFinalityDepth = 10000 PersistenceEnabled = true From ddce6304a8bce145cf303687ca3f66d0aa13874e Mon Sep 17 00:00:00 2001 From: Street <5597260+MStreet3@users.noreply.github.com> Date: Thu, 30 Jan 2025 14:37:48 -0500 Subject: [PATCH 15/43] [CAPPL-434] feat(deployment/keystone): addNodes generate MCMS proposal (#16098) * fix(keystone/changeset): register nodes via mcms proposal * fix(keystone/changeset): adds unit test for add don mcms proposal * refactor(keyston/changeset): minor refactor * fix(keystone/changeset): lint test file * fix path spec in GNUMakefile * fix(deployment/keystone): find nodes to compare instead of iterate * fix: update nodes test --- GNUmakefile | 2 +- .../keystone/changeset/internal/deploy.go | 99 +++++-- .../changeset/internal/deploy_test.go | 262 +++++++++++++++++- .../keystone/changeset/internal/test/utils.go | 185 ++++++++++--- .../changeset/internal/update_nodes_test.go | 42 ++- 5 files changed, 508 insertions(+), 82 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index e41a3240073..a7ced725619 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -111,7 +111,7 @@ abigen: ## Build & install abigen. .PHONY: generate generate: abigen codecgen mockery protoc gomods ## Execute all go:generate commands. ## Updating PATH makes sure that go:generate uses the version of protoc installed by the protoc make command. - export PATH=$(HOME)/.local/bin:$(PATH); gomods -w go generate -x ./... + export PATH="$(HOME)/.local/bin:$(PATH)"; gomods -w go generate -x ./... find . -type f -name .mockery.yaml -execdir mockery \; ## Execute mockery for all .mockery.yaml files .PHONY: rm-mocked diff --git a/deployment/keystone/changeset/internal/deploy.go b/deployment/keystone/changeset/internal/deploy.go index 8b67013aa15..be4c3a192b8 100644 --- a/deployment/keystone/changeset/internal/deploy.go +++ b/deployment/keystone/changeset/internal/deploy.go @@ -668,16 +668,21 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode } nodeIDToParams := make(map[string]capabilities_registry.CapabilitiesRegistryNodeParams) + nodeIDToDon := make(map[string]string) for don, nodes := range req.DonToNodes { caps, ok := req.DonToCapabilities[don] if !ok { return nil, fmt.Errorf("capabilities not found for don %s", don) } - var hashedCapabilityIds [][32]byte + var ( + hashedCapabilityIDs [][32]byte + capIDs []string + ) for _, cap := range caps { - hashedCapabilityIds = append(hashedCapabilityIds, cap.ID) + hashedCapabilityIDs = append(hashedCapabilityIDs, cap.ID) + capIDs = append(capIDs, hex.EncodeToString(cap.ID[:])) } - lggr.Debugw("hashed capability ids", "don", don, "ids", hashedCapabilityIds) + lggr.Debugw("hashed capability ids", "don", don, "ids", capIDs) for _, n := range nodes { if n.IsBootstrap { // bootstraps are part of the DON but don't host capabilities @@ -703,37 +708,50 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode Signer: signer, P2pId: n.PeerID, EncryptionPublicKey: csakey, - HashedCapabilityIds: hashedCapabilityIds, + HashedCapabilityIds: hashedCapabilityIDs, } } else { // when we have a node operator, we need to dedup capabilities against the existing ones - var newCapIds [][32]byte - for _, proposedCapId := range hashedCapabilityIds { + var newCapIDs [][32]byte + for _, proposedCapID := range hashedCapabilityIDs { shouldAdd := true - for _, existingCapId := range params.HashedCapabilityIds { - if existingCapId == proposedCapId { + for _, existingCapID := range params.HashedCapabilityIds { + if existingCapID == proposedCapID { shouldAdd = false break } } if shouldAdd { - newCapIds = append(newCapIds, proposedCapId) + newCapIDs = append(newCapIDs, proposedCapID) } } - params.HashedCapabilityIds = append(params.HashedCapabilityIds, newCapIds...) + params.HashedCapabilityIds = append(params.HashedCapabilityIds, newCapIDs...) } nodeIDToParams[n.NodeID] = params + nodeIDToDon[n.NodeID] = don } } - var uniqueNodeParams []capabilities_registry.CapabilitiesRegistryNodeParams - for _, v := range nodeIDToParams { - uniqueNodeParams = append(uniqueNodeParams, v) + lggr.Debugw("checking for existing nodes", "count", len(nodeIDToParams)) + + nodes2Add, err := getNodesToRegister(registry, nodeIDToParams) + if err != nil { + return nil, fmt.Errorf("failed to get nodes to register: %w", err) + } + + lggr.Debugf("found %d missing nodes", len(nodes2Add)) + + if len(nodes2Add) == 0 { + lggr.Debug("no new nodes to register") + return &RegisterNodesResponse{ + nodeIDToParams: nodeIDToParams, + }, nil } - lggr.Debugw("unique node params to add", "count", len(uniqueNodeParams), "params", uniqueNodeParams) + + lggr.Debugw("unique node params to add after deduplication", "count", len(nodes2Add), "params", nodes2Add) if req.UseMCMS { - ops, err := addNodesMCMSProposal(registry, uniqueNodeParams, registryChain) + ops, err := addNodesMCMSProposal(registry, nodes2Add, registryChain) if err != nil { return nil, fmt.Errorf("failed to generate proposal to add nodes: %w", err) } @@ -744,7 +762,7 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode }, nil } - tx, err := registry.AddNodes(registryChain.DeployerKey, uniqueNodeParams) + tx, err := registry.AddNodes(registryChain.DeployerKey, nodes2Add) if err != nil { err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err) // no typed errors in the abi, so we have to do string matching @@ -753,7 +771,7 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode return nil, fmt.Errorf("failed to call AddNodes for bulk add nodes: %w", err) } lggr.Warn("nodes already exist, falling back to 1-by-1") - for _, singleNodeParams := range uniqueNodeParams { + for _, singleNodeParams := range nodes2Add { tx, err = registry.AddNodes(registryChain.DeployerKey, []capabilities_registry.CapabilitiesRegistryNodeParams{singleNodeParams}) if err != nil { err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err) @@ -783,6 +801,34 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode }, nil } +// getNodesToRegister returns the nodes that are not already registered in the registry +func getNodesToRegister( + registry *capabilities_registry.CapabilitiesRegistry, + nodeIDToParams map[string]capabilities_registry.CapabilitiesRegistryNodeParams, +) ([]capabilities_registry.CapabilitiesRegistryNodeParams, error) { + nodes2Add := make([]capabilities_registry.CapabilitiesRegistryNodeParams, 0) + for nodeID, nodeParams := range nodeIDToParams { + var ( + ni capabilities_registry.INodeInfoProviderNodeInfo + err error + ) + if ni, err = registry.GetNode(&bind.CallOpts{}, nodeParams.P2pId); err != nil { + if err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err); strings.Contains(err.Error(), "NodeDoesNotExist") { + nodes2Add = append(nodes2Add, nodeParams) + continue + } + return nil, fmt.Errorf("failed to call GetNode for node %s: %w", nodeID, err) + } + + // if no error, but node info is empty, then the node does not exist and should be added. + if hex.EncodeToString(ni.P2pId[:]) != hex.EncodeToString(nodeParams.P2pId[:]) && hex.EncodeToString(ni.P2pId[:]) == "0000000000000000000000000000000000000000000000000000000000000000" { + nodes2Add = append(nodes2Add, nodeParams) + continue + } + } + return nodes2Add, nil +} + // addNodesMCMSProposal generates a single call to AddNodes for all the node params at once. func addNodesMCMSProposal(registry *capabilities_registry.CapabilitiesRegistry, params []capabilities_registry.CapabilitiesRegistryNodeParams, regChain deployment.Chain) (*timelock.BatchChainOperation, error) { tx, err := registry.AddNodes(deployment.SimTransactOpts(), params) @@ -857,7 +903,7 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes } lggr.Infow("fetched existing DONs...", "len", len(donInfos), "lenByNodesHash", len(existingDONs)) - mcmsOps := make([]mcms.Operation, 0, len(req.DonsToRegister)) + mcmsOps := make([]mcms.Operation, 0) for _, don := range req.DonsToRegister { var p2pIds [][32]byte for _, n := range don.Nodes { @@ -908,6 +954,8 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes txOpts = deployment.SimTransactOpts() } + lggr.Debugw("calling add don", "don", don.Name, "p2p sorted hash", p2pSortedHash, "cgs", cfgs, "wfSupported", wfSupported, "f", don.F, + "p2pids", p2pIds, "node count", len(p2pIds)) tx, err := registry.AddDON(txOpts, p2pIds, cfgs, true, wfSupported, don.F) if err != nil { err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err) @@ -934,12 +982,15 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes } if req.UseMCMS { - return &RegisterDonsResponse{ - Ops: &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(registryChain.Selector), - Batch: mcmsOps, - }, - }, nil + if len(mcmsOps) > 0 { + return &RegisterDonsResponse{ + Ops: &timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(registryChain.Selector), + Batch: mcmsOps, + }, + }, nil + } + return &RegisterDonsResponse{}, nil } lggr.Debugf("Registered all DONs (new=%d), waiting for registry to update", addedDons) diff --git a/deployment/keystone/changeset/internal/deploy_test.go b/deployment/keystone/changeset/internal/deploy_test.go index c059cd5a981..5b37b397026 100644 --- a/deployment/keystone/changeset/internal/deploy_test.go +++ b/deployment/keystone/changeset/internal/deploy_test.go @@ -6,12 +6,14 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-common/pkg/logger" + chain_selectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) func Test_RegisterNOPS(t *testing.T) { @@ -86,13 +88,71 @@ func Test_AddCapabilities(t *testing.T) { func Test_RegisterNodes(t *testing.T) { var ( - useMCMS bool - lggr = logger.Test(t) - setupResp = kstest.SetupTestRegistry(t, lggr, &kstest.SetupTestRegistryRequest{}) - registry = setupResp.Registry - chain = setupResp.Chain + useMCMS bool + lggr = logger.Test(t) + existingNOP = testNop(t, "testNop") + initialp2pToCapabilities = map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability{ + testPeerID(t, "0x1"): { + { + LabelledName: "test", + Version: "1.0.0", + CapabilityType: 0, + }, + }, + } + nopToNodes = map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc{ + existingNOP: { + { + Signer: [32]byte{0: 1}, + P2PKey: testPeerID(t, "0x1"), + EncryptionPublicKey: [32]byte{3: 16, 4: 2}, + }, + }, + } + + setupResp = kstest.SetupTestRegistry(t, lggr, &kstest.SetupTestRegistryRequest{ + P2pToCapabilities: initialp2pToCapabilities, + NopToNodes: nopToNodes, + }) + registry = setupResp.Registry + chain = setupResp.Chain + + registeredCapabilities = kstest.GetRegisteredCapabilities(t, lggr, initialp2pToCapabilities, setupResp.CapabilityCache) + + registeredNodeParams = kstest.ToNodeParams(t, nopToNodes, + kstest.ToP2PToCapabilities(t, initialp2pToCapabilities, registry, registeredCapabilities), + ) ) t.Run("success create add nodes mcms proposal", func(t *testing.T) { + var ( + nop2Add = testNop(t, "newNop") + caps2Add = map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability{ + testPeerID(t, "0x2"): { + { + LabelledName: "new-cap", + Version: "1.0.0", + CapabilityType: 0, + }, + }, + } + + nopToNodes = map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc{ + nop2Add: { + { + Signer: [32]byte{0: 1}, + P2PKey: testPeerID(t, "0x2"), + EncryptionPublicKey: [32]byte{3: 16, 4: 2}, + }, + }, + } + + rc, _ = kstest.MustAddCapabilities(t, lggr, caps2Add, chain, registry) + + nps = kstest.ToNodeParams(t, nopToNodes, + kstest.ToP2PToCapabilities(t, caps2Add, registry, rc), + ) + ) + useMCMS = true env := &deployment.Environment{ Logger: lggr, @@ -112,11 +172,109 @@ func Test_RegisterNodes(t *testing.T) { Env: env, RegistryChainSelector: chain.Selector, UseMCMS: useMCMS, + DonToCapabilities: map[string][]internal.RegisteredCapability{ + "testDON": rc, + }, + NopToNodeIDs: map[kcr.CapabilitiesRegistryNodeOperator][]string{ + nop2Add: {"node-id"}, + }, + DonToNodes: map[string][]deployment.Node{ + "testDON": { + { + PeerID: nps[0].P2pId, + NodeID: "node-id", + SelToOCRConfig: map[chain_selectors.ChainDetails]deployment.OCRConfig{ + { + ChainSelector: chain.Selector, + }: {}, + }, + }, + }, + }, + Nops: []*kcr.CapabilitiesRegistryNodeOperatorAdded{{ + Name: nop2Add.Name, + Admin: nop2Add.Admin, + NodeOperatorId: 2, + }}, }) require.NoError(t, err) require.NotNil(t, resp.Ops) require.Len(t, resp.Ops.Batch, 1) }) + + t.Run("no ops in proposal if node already exists", func(t *testing.T) { + useMCMS = true + env := &deployment.Environment{ + Logger: lggr, + Chains: map[uint64]deployment.Chain{ + chain.Selector: chain, + }, + ExistingAddresses: deployment.NewMemoryAddressBookFromMap(map[uint64]map[string]deployment.TypeAndVersion{ + chain.Selector: { + registry.Address().String(): deployment.TypeAndVersion{ + Type: internal.CapabilitiesRegistry, + Version: deployment.Version1_0_0, + }, + }, + }), + } + resp, err := internal.RegisterNodes(lggr, &internal.RegisterNodesRequest{ + Env: env, + RegistryChainSelector: chain.Selector, + UseMCMS: useMCMS, + DonToCapabilities: map[string][]internal.RegisteredCapability{ + "testDON": registeredCapabilities, + }, + NopToNodeIDs: map[kcr.CapabilitiesRegistryNodeOperator][]string{ + existingNOP: {"node-id"}, + }, + DonToNodes: map[string][]deployment.Node{ + "testDON": { + { + PeerID: registeredNodeParams[0].P2pId, + NodeID: "node-id", + SelToOCRConfig: map[chain_selectors.ChainDetails]deployment.OCRConfig{ + { + ChainSelector: chain.Selector, + }: {}, + }, + }, + }, + }, + Nops: []*kcr.CapabilitiesRegistryNodeOperatorAdded{{ + Name: existingNOP.Name, + Admin: existingNOP.Admin, + NodeOperatorId: 1, + }}, + }) + require.NoError(t, err) + require.Nil(t, resp.Ops) + }) + + t.Run("no new nodes to add results in no mcms ops", func(t *testing.T) { + useMCMS = true + env := &deployment.Environment{ + Logger: lggr, + Chains: map[uint64]deployment.Chain{ + chain.Selector: chain, + }, + ExistingAddresses: deployment.NewMemoryAddressBookFromMap(map[uint64]map[string]deployment.TypeAndVersion{ + chain.Selector: { + registry.Address().String(): deployment.TypeAndVersion{ + Type: internal.CapabilitiesRegistry, + Version: deployment.Version1_0_0, + }, + }, + }), + } + resp, err := internal.RegisterNodes(lggr, &internal.RegisterNodesRequest{ + Env: env, + RegistryChainSelector: chain.Selector, + UseMCMS: useMCMS, + }) + require.NoError(t, err) + require.Nil(t, resp.Ops) + }) } func Test_RegisterDons(t *testing.T) { @@ -162,6 +320,98 @@ func Test_RegisterDons(t *testing.T) { require.Len(t, resp.Ops.Batch, 1) }) + t.Run("no new dons to add results in no mcms ops", func(t *testing.T) { + var ( + existingNOP = testNop(t, "testNop") + existingP2Pkey = testPeerID(t, "0x1") + initialp2pToCapabilities = map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability{ + existingP2Pkey: { + { + LabelledName: "test", + Version: "1.0.0", + CapabilityType: 0, + }, + }, + testPeerID(t, "0x2"): { + { + LabelledName: "test", + Version: "1.0.0", + CapabilityType: 0, + }, + }, + testPeerID(t, "0x3"): { + { + LabelledName: "test", + Version: "1.0.0", + CapabilityType: 0, + }, + }, + } + nopToNodes = map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc{ + existingNOP: { + { + Signer: [32]byte{0: 1}, + P2PKey: existingP2Pkey, + EncryptionPublicKey: [32]byte{3: 16, 4: 2}, + }, + { + Signer: [32]byte{0: 1, 1: 1}, + P2PKey: testPeerID(t, "0x2"), + EncryptionPublicKey: [32]byte{3: 16, 4: 2}, + }, + { + Signer: [32]byte{0: 1, 1: 1, 2: 1}, + P2PKey: testPeerID(t, "0x3"), + EncryptionPublicKey: [32]byte{3: 16, 4: 2}, + }, + }, + } + + setupResp = kstest.SetupTestRegistry(t, lggr, &kstest.SetupTestRegistryRequest{ + P2pToCapabilities: initialp2pToCapabilities, + NopToNodes: nopToNodes, + Dons: []kstest.Don{ + { + Name: "test-don", + P2PIDs: []p2pkey.PeerID{existingP2Pkey, testPeerID(t, "0x2"), testPeerID(t, "0x3")}, + }, + }, + }) + regContract = setupResp.Registry + ) + + env := &deployment.Environment{ + Logger: lggr, + Chains: map[uint64]deployment.Chain{ + setupResp.Chain.Selector: setupResp.Chain, + }, + ExistingAddresses: deployment.NewMemoryAddressBookFromMap(map[uint64]map[string]deployment.TypeAndVersion{ + setupResp.Chain.Selector: { + regContract.Address().String(): deployment.TypeAndVersion{ + Type: internal.CapabilitiesRegistry, + Version: deployment.Version1_0_0, + }, + }, + }), + } + resp, err := internal.RegisterDons(lggr, internal.RegisterDonsRequest{ + Env: env, + RegistryChainSelector: setupResp.Chain.Selector, + DonToCapabilities: map[string][]internal.RegisteredCapability{ + "test-don": {}, + }, + DonsToRegister: []internal.DONToRegister{ + { + Name: "test-don", + F: 1, + }, + }, + UseMCMS: true, + }) + require.NoError(t, err) + require.Nil(t, resp.Ops) + }) + t.Run("success create add DONs mcms proposal with multiple DONs", func(t *testing.T) { useMCMS = true env := &deployment.Environment{ diff --git a/deployment/keystone/changeset/internal/test/utils.go b/deployment/keystone/changeset/internal/test/utils.go index 290d0ee2196..f5d078e7521 100644 --- a/deployment/keystone/changeset/internal/test/utils.go +++ b/deployment/keystone/changeset/internal/test/utils.go @@ -30,9 +30,14 @@ type Don struct { } type SetupTestRegistryRequest struct { + // P2pToCapabilities maps a node's p2pID to the capabilities it has P2pToCapabilities map[p2pkey.PeerID][]capabilities_registry.CapabilitiesRegistryCapability - NopToNodes map[capabilities_registry.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc - Dons []Don + + // NopToNodes maps a node operator to the nodes they operate + NopToNodes map[capabilities_registry.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc + + // Dons groups the p2pIDs of the nodes that comprise it and the capabilities they have + Dons []Don // TODO maybe add support for MCMS at this level } @@ -41,70 +46,157 @@ type SetupTestRegistryResponse struct { Chain deployment.Chain RegistrySelector uint64 ContractSet *internal.ContractSet + CapabilityCache *CapabilityCache } func SetupTestRegistry(t *testing.T, lggr logger.Logger, req *SetupTestRegistryRequest) *SetupTestRegistryResponse { chain := testChain(t) + // deploy the registry registry := deployCapReg(t, chain) + // convert req to nodeoperators + nops := ToNodeOps(t, req.NopToNodes) + addNopsResp := addNops(t, lggr, chain, registry, nops) + require.Len(t, addNopsResp.Nops, len(nops)) + + // add capabilities to registry + registeredCapabilities, capCache := MustAddCapabilities(t, lggr, req.P2pToCapabilities, chain, registry) + + // make the nodes and register node + nodeParams := ToNodeParams(t, + req.NopToNodes, + ToP2PToCapabilities(t, req.P2pToCapabilities, registry, registeredCapabilities), + ) + + AddNodes(t, lggr, chain, registry, nodeParams) + + // add the Dons + addDons(t, lggr, chain, registry, capCache, req.Dons) + + return &SetupTestRegistryResponse{ + Registry: registry, + Chain: chain, + RegistrySelector: chain.Selector, + ContractSet: &internal.ContractSet{ + CapabilitiesRegistry: registry, + }, + CapabilityCache: capCache, + } +} + +// ToNodeParams transforms a map of node operators to nops and a map of node p2pID to capabilities +// into a slice of node params required to register the nodes. The number of capabilities +// must match the number of nodes. +func ToNodeParams(t *testing.T, + nop2Nodes map[capabilities_registry.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc, + p2pToCapabilities map[p2pkey.PeerID][][32]byte, +) []capabilities_registry.CapabilitiesRegistryNodeParams { + t.Helper() + + var nodeParams []capabilities_registry.CapabilitiesRegistryNodeParams + var i uint32 + for _, p2pSignerEncs := range nop2Nodes { + for _, p2pSignerEnc := range p2pSignerEncs { + _, exists := p2pToCapabilities[p2pSignerEnc.P2PKey] + require.True(t, exists, "missing capabilities for p2pID %s", p2pSignerEnc.P2PKey) + + nodeParams = append(nodeParams, capabilities_registry.CapabilitiesRegistryNodeParams{ + Signer: p2pSignerEnc.Signer, + P2pId: p2pSignerEnc.P2PKey, + EncryptionPublicKey: p2pSignerEnc.EncryptionPublicKey, + HashedCapabilityIds: p2pToCapabilities[p2pSignerEnc.P2PKey], + NodeOperatorId: i + 1, + }) + } + i++ + } + + return nodeParams +} + +func ToNodeOps( + t *testing.T, + nop2Nodes map[capabilities_registry.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc, +) []capabilities_registry.CapabilitiesRegistryNodeOperator { + t.Helper() + nops := make([]capabilities_registry.CapabilitiesRegistryNodeOperator, 0) - for nop := range req.NopToNodes { + for nop := range nop2Nodes { nops = append(nops, nop) } + sort.Slice(nops, func(i, j int) bool { return nops[i].Name < nops[j].Name }) - addNopsResp := addNops(t, lggr, chain, registry, nops) - require.Len(t, addNopsResp.Nops, len(nops)) + return nops +} - // add capabilities to registry - capCache := NewCapabiltyCache(t) +// MustAddCapabilities adds the capabilities to the registry and returns the registered capabilities +// if the capability is already registered, this call will fail. +func MustAddCapabilities( + t *testing.T, + lggr logger.Logger, + in map[p2pkey.PeerID][]capabilities_registry.CapabilitiesRegistryCapability, + chain deployment.Chain, + registry *capabilities_registry.CapabilitiesRegistry, +) ([]internal.RegisteredCapability, *CapabilityCache) { + t.Helper() + cache := NewCapabiltyCache(t) var capabilities []capabilities_registry.CapabilitiesRegistryCapability - for _, caps := range req.P2pToCapabilities { + for _, caps := range in { capabilities = append(capabilities, caps...) } - registeredCapabilities := capCache.AddCapabilities(lggr, chain, registry, capabilities) + + registeredCapabilities := cache.AddCapabilities(lggr, chain, registry, capabilities) expectedDeduped := make(map[capabilities_registry.CapabilitiesRegistryCapability]struct{}) for _, cap := range capabilities { expectedDeduped[cap] = struct{}{} } require.Len(t, registeredCapabilities, len(expectedDeduped)) + return registeredCapabilities, cache +} - // make the nodes and register node - var nodeParams []capabilities_registry.CapabilitiesRegistryNodeParams - initialp2pToCapabilities := make(map[p2pkey.PeerID][][32]byte) - for p2pID := range req.P2pToCapabilities { - initialp2pToCapabilities[p2pID] = mustCapabilityIds(t, registry, registeredCapabilities) +// GetRegisteredCapabilities returns the registered capabilities for the given capabilities. Each +// capability must exist on the cache already. +func GetRegisteredCapabilities( + t *testing.T, + lggr logger.Logger, + in map[p2pkey.PeerID][]capabilities_registry.CapabilitiesRegistryCapability, + cache *CapabilityCache, +) []internal.RegisteredCapability { + t.Helper() + + var capabilities []capabilities_registry.CapabilitiesRegistryCapability + for _, caps := range in { + capabilities = append(capabilities, caps...) } - // create node with initial capabilities assigned to nop - for i, nop := range nops { - if _, exists := req.NopToNodes[nop]; !exists { - require.Fail(t, "missing nopToNodes for %s", nop.Name) - } - for _, p2pSignerEnc := range req.NopToNodes[nop] { - nodeParams = append(nodeParams, capabilities_registry.CapabilitiesRegistryNodeParams{ - Signer: p2pSignerEnc.Signer, - P2pId: p2pSignerEnc.P2PKey, - EncryptionPublicKey: p2pSignerEnc.EncryptionPublicKey, - HashedCapabilityIds: initialp2pToCapabilities[p2pSignerEnc.P2PKey], - NodeOperatorId: uint32(i + 1), // nopid in contract is 1-indexed - }) - } + + registeredCapabilities := make([]internal.RegisteredCapability, 0) + for _, cap := range capabilities { + id, exists := cache.Get(cap) + require.True(t, exists, "capability not found in cache %v", cap) + registeredCapabilities = append(registeredCapabilities, internal.RegisteredCapability{ + CapabilitiesRegistryCapability: cap, + ID: id, + }) } - addNodes(t, lggr, chain, registry, nodeParams) - // add the Dons - addDons(t, lggr, chain, registry, capCache, req.Dons) + return registeredCapabilities +} - return &SetupTestRegistryResponse{ - Registry: registry, - Chain: chain, - RegistrySelector: chain.Selector, - ContractSet: &internal.ContractSet{ - CapabilitiesRegistry: registry, - }, +func ToP2PToCapabilities( + t *testing.T, + in map[p2pkey.PeerID][]capabilities_registry.CapabilitiesRegistryCapability, + registry *capabilities_registry.CapabilitiesRegistry, + caps []internal.RegisteredCapability, +) map[p2pkey.PeerID][][32]byte { + t.Helper() + out := make(map[p2pkey.PeerID][][32]byte) + for p2pID := range in { + out[p2pID] = mustCapabilityIds(t, registry, caps) } + return out } func deployCapReg(t *testing.T, chain deployment.Chain) *capabilities_registry.CapabilitiesRegistry { @@ -139,7 +231,13 @@ func addNops(t *testing.T, lggr logger.Logger, chain deployment.Chain, registry return resp } -func addNodes(t *testing.T, lggr logger.Logger, chain deployment.Chain, registry *capabilities_registry.CapabilitiesRegistry, nodes []capabilities_registry.CapabilitiesRegistryNodeParams) { +func AddNodes( + t *testing.T, + lggr logger.Logger, + chain deployment.Chain, + registry *capabilities_registry.CapabilitiesRegistry, + nodes []capabilities_registry.CapabilitiesRegistryNodeParams, +) { tx, err := registry.AddNodes(chain.DeployerKey, nodes) if err != nil { err2 := deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err) @@ -149,7 +247,14 @@ func addNodes(t *testing.T, lggr logger.Logger, chain deployment.Chain, registry require.NoError(t, err) } -func addDons(t *testing.T, lggr logger.Logger, chain deployment.Chain, registry *capabilities_registry.CapabilitiesRegistry, capCache *CapabilityCache, dons []Don) { +func addDons( + t *testing.T, + _ logger.Logger, + chain deployment.Chain, + registry *capabilities_registry.CapabilitiesRegistry, + capCache *CapabilityCache, + dons []Don, +) { for _, don := range dons { acceptsWorkflows := false // lookup the capabilities diff --git a/deployment/keystone/changeset/internal/update_nodes_test.go b/deployment/keystone/changeset/internal/update_nodes_test.go index 642eaebbe4d..fc565c699b2 100644 --- a/deployment/keystone/changeset/internal/update_nodes_test.go +++ b/deployment/keystone/changeset/internal/update_nodes_test.go @@ -276,12 +276,13 @@ func TestUpdateNodes(t *testing.T) { wantErr: false, }, { - name: "twos node, different capabilities", + name: "twos nodes with different capabilities", args: args{ lggr: lggr, req: &internal.UpdateNodesRequest{ P2pToUpdates: map[p2pkey.PeerID]internal.NodeUpdate{ - testPeerID(t, "peerID_1"): internal.NodeUpdate{ + testPeerID(t, "peerID_1"): { + NodeOperatorID: 1, Capabilities: []kcr.CapabilitiesRegistryCapability{ { LabelledName: "cap1", @@ -290,7 +291,8 @@ func TestUpdateNodes(t *testing.T) { }, }, }, - testPeerID(t, "peerID_2"): internal.NodeUpdate{ + testPeerID(t, "peerID_2"): { + NodeOperatorID: 2, Capabilities: []kcr.CapabilitiesRegistryCapability{ { LabelledName: "cap2", @@ -303,14 +305,14 @@ func TestUpdateNodes(t *testing.T) { Chain: chain, }, nopsToNodes: map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc{ - testNop(t, "nopA"): []*internal.P2PSignerEnc{ + testNop(t, "nopA"): { { P2PKey: testPeerID(t, "peerID_1"), Signer: [32]byte{0: 1, 31: 1}, EncryptionPublicKey: [32]byte{0: 7, 1: 7}, }, }, - testNop(t, "nopB"): []*internal.P2PSignerEnc{ + testNop(t, "nopB"): { { P2PKey: testPeerID(t, "peerID_2"), Signer: [32]byte{0: 2, 31: 2}, @@ -496,12 +498,12 @@ func TestUpdateNodes(t *testing.T) { t.Errorf("UpdateNodes() error = %v, wantErr %v", err, tt.wantErr) return } - for i, p := range got.NodeParams { - expected := tt.want.NodeParams[i] - require.Equal(t, expected.NodeOperatorId, p.NodeOperatorId) - require.Equal(t, expected.P2pId, p.P2pId) - require.Equal(t, expected.Signer, p.Signer) - require.Equal(t, expected.EncryptionPublicKey, p.EncryptionPublicKey) + + for _, p := range got.NodeParams { + // check the node params + expected := findNodeParams(t, tt.want.NodeParams, p.P2pId) + assertNodeParams(t, expected, p) + // check the capabilities expectedCaps := expectedUpdatedCaps[p.P2pId] var wantHashedIDs [][32]byte @@ -703,3 +705,21 @@ func testNop(t *testing.T, name string) kcr.CapabilitiesRegistryNodeOperator { Name: name, } } + +func findNodeParams(t *testing.T, nodes []kcr.CapabilitiesRegistryNodeParams, p2p p2pkey.PeerID) kcr.CapabilitiesRegistryNodeParams { + for _, n := range nodes { + if n.P2pId == p2p { + return n + } + } + require.Failf(t, "could not find node %s", p2p.String()) + return kcr.CapabilitiesRegistryNodeParams{} +} + +func assertNodeParams(t *testing.T, expected, got kcr.CapabilitiesRegistryNodeParams) { + t.Helper() + assert.Equal(t, expected.P2pId, got.P2pId, "p2p ID failed : expected %v, got %v", expected.P2pId, got.P2pId) + assert.Equal(t, expected.NodeOperatorId, got.NodeOperatorId, "nop ID failed : expected %d, got %d", expected.NodeOperatorId, got.NodeOperatorId) + assert.Equal(t, expected.Signer, got.Signer, "signer failed : expected %v, got %v", expected.Signer, got.Signer) + assert.Equal(t, expected.EncryptionPublicKey, got.EncryptionPublicKey, "encryption key failed : expected %v, got %v", expected.EncryptionPublicKey, got.EncryptionPublicKey) +} From 9b1fdce556ba3c2243f7deeca5662ae441c5efc2 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 30 Jan 2025 15:05:28 -0500 Subject: [PATCH 16/43] Re-enable info-level OCR logging for LLO (#16122) * Re-enable info-level OCR logging for LLO * Changeset * log poller optimization * Add additional info to LLO OCR logging * Fixes test --------- Co-authored-by: vyzaldysanchez --- .changeset/serious-suns-flow.md | 5 ++ core/services/llo/delegate.go | 2 +- core/services/llo/suppressed_logger.go | 24 +++---- core/services/ocr2/delegate.go | 4 +- core/services/relay/evm/evm.go | 4 +- core/services/relay/evm/llo/config_poller.go | 67 +++++++++++++------- core/services/relay/evm/write_target_test.go | 2 +- 7 files changed, 69 insertions(+), 39 deletions(-) create mode 100644 .changeset/serious-suns-flow.md diff --git a/.changeset/serious-suns-flow.md b/.changeset/serious-suns-flow.md new file mode 100644 index 00000000000..bdf2972551a --- /dev/null +++ b/.changeset/serious-suns-flow.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Only show OCR info-level logs with VerboseLogging #internal diff --git a/core/services/llo/delegate.go b/core/services/llo/delegate.go index 0c7d539427e..8d70a669ffa 100644 --- a/core/services/llo/delegate.go +++ b/core/services/llo/delegate.go @@ -135,7 +135,7 @@ func (d *delegate) Start(ctx context.Context) error { case 1: lggr = logger.With(lggr, "instanceType", "Green") } - ocrLogger := logger.NewOCRWrapper(NewSuppressedLogger(lggr, d.cfg.ReportingPluginConfig.VerboseLogging), d.cfg.TraceLogging, func(msg string) { + ocrLogger := logger.NewOCRWrapper(NewSuppressedLogger(lggr, d.cfg.TraceLogging, d.cfg.ReportingPluginConfig.VerboseLogging), d.cfg.TraceLogging, func(msg string) { // NOTE: Some OCR loggers include a DB-persist here // We do not DB persist errors in LLO, since they could be quite voluminous and ought to be present in logs anyway. // This is a performance optimization diff --git a/core/services/llo/suppressed_logger.go b/core/services/llo/suppressed_logger.go index 9fe6e6731e5..764e484ca9f 100644 --- a/core/services/llo/suppressed_logger.go +++ b/core/services/llo/suppressed_logger.go @@ -2,50 +2,52 @@ package llo import "github.com/smartcontractkit/chainlink-common/pkg/logger" -// Suppressed logger swallows debug/info unless the verbose flag is turned on +// Suppressed logger swallows debug and/or info levels // Useful for OCR to calm down its verbosity var _ logger.Logger = &SuppressedLogger{} -func NewSuppressedLogger(lggr logger.Logger, verbose bool) logger.Logger { +func NewSuppressedLogger(lggr logger.Logger, debug, info bool) logger.Logger { return &SuppressedLogger{ - Logger: lggr, - Verbose: verbose, + Logger: lggr, + DebugLevel: debug, + InfoLevel: info, } } type SuppressedLogger struct { logger.Logger - Verbose bool + DebugLevel bool + InfoLevel bool } func (s *SuppressedLogger) Debug(args ...interface{}) { - if s.Verbose { + if s.DebugLevel { s.Logger.Debug(args...) } } func (s *SuppressedLogger) Info(args ...interface{}) { - if s.Verbose { + if s.InfoLevel { s.Logger.Info(args...) } } func (s *SuppressedLogger) Debugf(format string, values ...interface{}) { - if s.Verbose { + if s.DebugLevel { s.Logger.Debugf(format, values...) } } func (s *SuppressedLogger) Infof(format string, values ...interface{}) { - if s.Verbose { + if s.InfoLevel { s.Logger.Infof(format, values...) } } func (s *SuppressedLogger) Debugw(msg string, keysAndValues ...interface{}) { - if s.Verbose { + if s.DebugLevel { s.Logger.Debugw(msg, keysAndValues...) } } func (s *SuppressedLogger) Infow(msg string, keysAndValues ...interface{}) { - if s.Verbose { + if s.InfoLevel { s.Logger.Infow(msg, keysAndValues...) } } diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index f4d92ca079e..f6657557929 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -885,7 +885,7 @@ func (d *Delegate) newServicesMercury( lc.ContractConfigTrackerPollInterval = 1 * time.Second // This is the fastest that libocr supports. See: https://github.com/smartcontractkit/offchain-reporting/pull/520 // Disable OCR debug+info logging for legacy mercury jobs unless tracelogging is enabled, because its simply too verbose (150 jobs => ~50k logs per second) - ocrLogger := ocrcommon.NewOCRWrapper(llo.NewSuppressedLogger(lggr, d.cfg.OCR2().TraceLogging()), d.cfg.OCR2().TraceLogging(), func(ctx context.Context, msg string) { + ocrLogger := ocrcommon.NewOCRWrapper(llo.NewSuppressedLogger(lggr, d.cfg.OCR2().TraceLogging(), d.cfg.OCR2().TraceLogging()), d.cfg.OCR2().TraceLogging(), func(ctx context.Context, msg string) { lggr.ErrorIf(d.jobORM.RecordError(ctx, jb.ID, msg), "unable to record error") }) @@ -946,7 +946,6 @@ func (d *Delegate) newServicesLLO( ocrDB *db, lc ocrtypes.LocalConfig, ) ([]job.ServiceCtx, error) { - lggr = logger.Sugared(lggr.Named("LLO")) spec := jb.OCR2OracleSpec transmitterID := spec.TransmitterID.String if len(transmitterID) != 64 { @@ -985,6 +984,7 @@ func (d *Delegate) newServicesLLO( if err = json.Unmarshal(spec.PluginConfig.Bytes(), &pluginCfg); err != nil { return nil, err } + lggr = logger.Sugared(lggr.Named("LLO").With("donID", pluginCfg.DonID, "channelDefinitionsContractAddress", pluginCfg.ChannelDefinitionsContractAddress)) // Handle key bundle IDs explicitly specified in job spec kbm := make(map[llotypes.ReportFormat]llo.Key) diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 18d10ca994f..91645a5ffe3 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -209,7 +209,7 @@ func NewRelayer(ctx context.Context, lggr logger.Logger, chain legacyevm.Chain, if err != nil { return nil, fmt.Errorf("cannot create evm relayer: %w", err) } - sugared := logger.Sugared(lggr).Named("Relayer") + sugared := logger.Sugared(lggr).Named("Relayer").With("evmChainID", chain.ID()) mercuryORM := mercury.NewORM(opts.DS) cdcFactory := sync.OnceValues(func() (llo.ChannelDefinitionCacheFactory, error) { chainSelector, err := chainselectors.SelectorFromChainId(chain.ID().Uint64()) @@ -836,7 +836,7 @@ func (r *Relayer) NewConfigProvider(ctx context.Context, args commontypes.RelayA // performance hit no matter how minor. configProvider, err = newLLOConfigProvider(ctx, lggr, r.chain, &llo.NullRetirementReportCache{}, relayOpts) case "ocr3-capability": - configProvider, err = newOCR3CapabilityConfigProvider(ctx, r.lggr, r.chain, relayOpts) + configProvider, err = newOCR3CapabilityConfigProvider(ctx, lggr, r.chain, relayOpts) default: return nil, fmt.Errorf("unrecognized provider type: %q", args.ProviderType) } diff --git a/core/services/relay/evm/llo/config_poller.go b/core/services/relay/evm/llo/config_poller.go index 43d60210ace..9865bea8632 100644 --- a/core/services/relay/evm/llo/config_poller.go +++ b/core/services/relay/evm/llo/config_poller.go @@ -4,10 +4,12 @@ import ( "bytes" "context" "database/sql" + "encoding/hex" "fmt" "math" "math/big" "strconv" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" @@ -60,7 +62,8 @@ type configPoller struct { donIDTopic [32]byte filterExprs []query.Expression - fromBlock uint64 + fromBlock int64 + mu sync.RWMutex instanceType InstanceType } @@ -100,7 +103,7 @@ func newConfigPoller(lggr logger.Logger, lp LogPoller, cc ConfigCache, addr comm donIDTopic: DonIDToBytes32(donID), filterExprs: exprs, instanceType: instanceType, - fromBlock: fromBlock, + fromBlock: int64(fromBlock), } cp.Service, cp.eng = services.Config{ Name: "LLOConfigPoller", @@ -115,11 +118,32 @@ func (cp *configPoller) Notify() <-chan struct{} { // LatestConfigDetails returns the latest config details from the logs func (cp *configPoller) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest ocrtypes.ConfigDigest, err error) { - latestConfig, log, err := cp.latestConfig(ctx, int64(cp.fromBlock), math.MaxInt64) // #nosec G115 + latestConfig, log, err := cp.latestConfig(ctx, cp.readFromBlock(), math.MaxInt64) if err != nil { return 0, ocrtypes.ConfigDigest{}, fmt.Errorf("failed to get latest config: %w", err) } - return uint64(log.BlockNumber), latestConfig.ConfigDigest, nil + // Slight optimization, since we only care about the latest log, we can + // avoid re-scanning from the original fromBlock every time by setting + // fromBlock to the latest seen log here. + // + // This should always be safe even if LatestConfigDetails is called + // concurrently. + cp.setFromBlock(log.BlockNumber) + return uint64(log.BlockNumber), latestConfig.ConfigDigest, nil // #nosec G115 // log.BlockNumber will never be negative +} + +func (cp *configPoller) readFromBlock() int64 { + cp.mu.RLock() + defer cp.mu.RUnlock() + return cp.fromBlock +} + +func (cp *configPoller) setFromBlock(fromBlock int64) { + cp.mu.Lock() + defer cp.mu.Unlock() + if fromBlock > cp.fromBlock { + cp.fromBlock = fromBlock + } } func (cp *configPoller) latestConfig(ctx context.Context, fromBlock, toBlock int64) (latestConfig FullConfigFromLog, latestLog logpoller.Log, err error) { @@ -150,7 +174,7 @@ func (cp *configPoller) latestConfig(ctx context.Context, fromBlock, toBlock int } if err = cp.cc.StoreConfig(ctx, event.ConfigDigest, event.Signers, event.F); err != nil { - cp.eng.SugaredLogger.Errorf("failed to store production config: %v", err) + cp.eng.Errorf("failed to store production config: %v", err) } isProduction := (cp.instanceType != InstanceTypeBlue) == event.IsGreenProduction @@ -168,7 +192,7 @@ func (cp *configPoller) latestConfig(ctx context.Context, fromBlock, toBlock int } if err = cp.cc.StoreConfig(ctx, event.ConfigDigest, event.Signers, event.F); err != nil { - cp.eng.SugaredLogger.Errorf("failed to store staging config: %v", err) + cp.eng.Errorf("failed to store staging config: %v", err) } isProduction := (cp.instanceType != InstanceTypeBlue) == event.IsGreenProduction @@ -190,10 +214,11 @@ func (cp *configPoller) latestConfig(ctx context.Context, fromBlock, toBlock int // LatestConfig returns the latest config from the logs starting from a certain block func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64) (ocrtypes.ContractConfig, error) { - cfg, _, err := cp.latestConfig(ctx, int64(changedInBlock), math.MaxInt64) // #nosec G115 + cfg, latestLog, err := cp.latestConfig(ctx, int64(changedInBlock), math.MaxInt64) // #nosec G115 if err != nil { return ocrtypes.ContractConfig{}, fmt.Errorf("failed to get latest config: %w", err) } + cp.eng.Infow("LatestConfig fetched", "config", cfg.ContractConfig, "txHash", latestLog.TxHash, "blockNumber", latestLog.BlockNumber, "blockHash", latestLog.BlockHash, "logIndex", latestLog.LogIndex, "instanceType", cp.instanceType, "donID", cp.donID, "changedInBlock", changedInBlock) return cfg.ContractConfig, nil } @@ -206,7 +231,7 @@ func (cp *configPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint } return 0, err } - return uint64(latest.BlockNumber), nil + return uint64(latest.BlockNumber), nil // #nosec G115 // latest.BlockNumber will never be negative } func (cp *configPoller) InstanceType() InstanceType { @@ -220,14 +245,13 @@ type FullConfigFromLog struct { } func FullConfigFromProductionConfigSet(unpacked configurator.ConfiguratorProductionConfigSet) (FullConfigFromLog, error) { - var transmitAccounts []ocrtypes.Account - for _, addr := range unpacked.OffchainTransmitters { - transmitAccounts = append(transmitAccounts, ocrtypes.Account(fmt.Sprintf("%x", addr))) + transmitAccounts := make([]ocrtypes.Account, len(unpacked.OffchainTransmitters)) + for i, addr := range unpacked.OffchainTransmitters { + transmitAccounts[i] = ocrtypes.Account(hex.EncodeToString(addr[:])) } - var signers []ocrtypes.OnchainPublicKey - for _, addr := range unpacked.Signers { - addr := addr - signers = append(signers, addr) + signers := make([]ocrtypes.OnchainPublicKey, len(unpacked.Signers)) + for i, addr := range unpacked.Signers { + signers[i] = addr } donIDBig := common.Hash(unpacked.ConfigId).Big() @@ -252,14 +276,13 @@ func FullConfigFromProductionConfigSet(unpacked configurator.ConfiguratorProduct } func FullConfigFromStagingConfigSet(unpacked configurator.ConfiguratorStagingConfigSet) (FullConfigFromLog, error) { - var transmitAccounts []ocrtypes.Account - for _, addr := range unpacked.OffchainTransmitters { - transmitAccounts = append(transmitAccounts, ocrtypes.Account(fmt.Sprintf("%x", addr))) + transmitAccounts := make([]ocrtypes.Account, len(unpacked.OffchainTransmitters)) + for i, addr := range unpacked.OffchainTransmitters { + transmitAccounts[i] = ocrtypes.Account(hex.EncodeToString(addr[:])) } - var signers []ocrtypes.OnchainPublicKey - for _, addr := range unpacked.Signers { - addr := addr - signers = append(signers, addr) + signers := make([]ocrtypes.OnchainPublicKey, len(unpacked.Signers)) + for i, addr := range unpacked.Signers { + signers[i] = addr } donIDBig := common.Hash(unpacked.ConfigId).Big() diff --git a/core/services/relay/evm/write_target_test.go b/core/services/relay/evm/write_target_test.go index 77deaf051c7..99a915c2376 100644 --- a/core/services/relay/evm/write_target_test.go +++ b/core/services/relay/evm/write_target_test.go @@ -264,12 +264,12 @@ func TestEvmWrite(t *testing.T) { testChain := evmmocks.NewChain(t) testCfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Workflow.FromAddress = nil - forwarderA := testutils.NewAddress() forwarderAddr, err2 := evmtypes.NewEIP55Address(forwarderA.Hex()) require.NoError(t, err2) c.EVM[0].Workflow.ForwarderAddress = &forwarderAddr }) + testChain.On("ID").Return(big.NewInt(11155111)) testChain.On("Config").Return(evmtest.NewChainScopedConfig(t, testCfg)) capabilityRegistry := evmcapabilities.NewRegistry(lggr) From 68c6c9cc78c2562573344c835d9b048f296d528b Mon Sep 17 00:00:00 2001 From: krehermann <16602512+krehermann@users.noreply.github.com> Date: Thu, 30 Jan 2025 14:56:35 -0700 Subject: [PATCH 17/43] remove confusing warn log (#16156) --- core/capabilities/launcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/capabilities/launcher.go b/core/capabilities/launcher.go index 719b3e872cc..d788b688bc0 100644 --- a/core/capabilities/launcher.go +++ b/core/capabilities/launcher.go @@ -329,7 +329,7 @@ func (w *launcher) addRemoteCapabilities(ctx context.Context, myDON registrysync return fmt.Errorf("failed to add action shim: %w", err) } case capabilities.CapabilityTypeConsensus: - w.lggr.Warn("no remote client configured for capability type consensus, skipping configuration") + // nothing to do; we don't support remote consensus capabilities for now case capabilities.CapabilityTypeTarget: newTargetFn := func(info capabilities.CapabilityInfo) (capabilityService, error) { client := executable.NewClient( From c81a1fad85efb38380e4c10274a1b1e627c08ca7 Mon Sep 17 00:00:00 2001 From: Anindita Ghosh <88458927+AnieeG@users.noreply.github.com> Date: Thu, 30 Jan 2025 15:24:41 -0800 Subject: [PATCH 18/43] Ccip-5024 setDynamicConfig on offRamp (#16158) * remove deployCCIPContracts * deprecate existing add lane * add setDynamicConfig on offRamp --- .../ccip/changeset/cs_chain_contracts.go | 130 +++++++++++++++++- .../ccip/changeset/cs_chain_contracts_test.go | 63 +++++++++ deployment/ccip/changeset/cs_deploy_chain.go | 8 +- 3 files changed, 191 insertions(+), 10 deletions(-) diff --git a/deployment/ccip/changeset/cs_chain_contracts.go b/deployment/ccip/changeset/cs_chain_contracts.go index 13265574511..f62192b4104 100644 --- a/deployment/ccip/changeset/cs_chain_contracts.go +++ b/deployment/ccip/changeset/cs_chain_contracts.go @@ -33,13 +33,14 @@ import ( ) var ( - _ 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 + _ deployment.ChangeSet[UpdateOnRampDestsConfig] = UpdateOnRampsDestsChangeset + _ deployment.ChangeSet[UpdateOffRampSourcesConfig] = UpdateOffRampSourcesChangeset + _ deployment.ChangeSet[UpdateRouterRampsConfig] = UpdateRouterRampsChangeset + _ deployment.ChangeSet[UpdateFeeQuoterDestsConfig] = UpdateFeeQuoterDestsChangeset + _ deployment.ChangeSet[SetOCR3OffRampConfig] = SetOCR3OffRampChangeset + _ deployment.ChangeSet[UpdateDynamicConfigOffRampConfig] = UpdateDynamicConfigOffRampChangeset + _ deployment.ChangeSet[UpdateFeeQuoterPricesConfig] = UpdateFeeQuoterPricesChangeset + _ deployment.ChangeSet[UpdateNonceManagerConfig] = UpdateNonceManagersChangeset ) type UpdateNonceManagerConfig struct { @@ -1082,6 +1083,121 @@ func SetOCR3OffRampChangeset(e deployment.Environment, cfg SetOCR3OffRampConfig) }}, nil } +type UpdateDynamicConfigOffRampConfig struct { + Updates map[uint64]OffRampParams + MCMS *MCMSConfig +} + +func (cfg UpdateDynamicConfigOffRampConfig) Validate(e deployment.Environment) error { + state, err := LoadOnchainState(e) + if err != nil { + return err + } + for chainSel, params := range cfg.Updates { + if deployment.IsValidChainSelector(chainSel) != nil { + return fmt.Errorf("invalid chain selector %d", chainSel) + } + if _, ok := state.Chains[chainSel]; !ok { + return fmt.Errorf("chain %d not found in onchain state", chainSel) + } + if state.Chains[chainSel].OffRamp == nil { + return fmt.Errorf("missing offramp for chain %d", chainSel) + } + if state.Chains[chainSel].FeeQuoter == nil { + return fmt.Errorf("missing fee quoter for chain %d", chainSel) + } + if state.Chains[chainSel].Timelock == nil { + return fmt.Errorf("missing timelock for chain %d", chainSel) + } + if params.GasForCallExactCheck > 0 { + e.Logger.Infow( + "GasForCallExactCheck is set, please note it's a static config and will be ignored for this changeset", + "chain", chainSel, "gas", params.GasForCallExactCheck) + } + if err := commoncs.ValidateOwnership( + e.GetContext(), + cfg.MCMS != nil, + e.Chains[chainSel].DeployerKey.From, + state.Chains[chainSel].Timelock.Address(), + state.Chains[chainSel].OffRamp, + ); err != nil { + return err + } + if err := params.Validate(true); err != nil { + return fmt.Errorf("chain %d: %w", chainSel, err) + } + } + return nil +} + +func UpdateDynamicConfigOffRampChangeset(e deployment.Environment, cfg UpdateDynamicConfigOffRampConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + state, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for chainSel, params := range cfg.Updates { + chain := e.Chains[chainSel] + txOpts := e.Chains[chainSel].DeployerKey + if cfg.MCMS != nil { + txOpts = deployment.SimTransactOpts() + } + offRamp := state.Chains[chainSel].OffRamp + dCfg := offramp.OffRampDynamicConfig{ + FeeQuoter: state.Chains[chainSel].FeeQuoter.Address(), + PermissionLessExecutionThresholdSeconds: params.PermissionLessExecutionThresholdSeconds, + IsRMNVerificationDisabled: params.IsRMNVerificationDisabled, + MessageInterceptor: params.MessageInterceptor, + } + tx, err := offRamp.SetDynamicConfig(txOpts, dCfg) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, offramp.OffRampABI) + } + e.Logger.Infow("Updated offramp dynamic config", "chain", chain.String(), "config", dCfg) + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chainSel), + Batch: []mcms.Operation{ + { + To: offRamp.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + p, err := proposalutils.BuildProposalFromBatches( + timelocks, + proposers, + batches, + "Update offramp dynamic config", + cfg.MCMS.MinDelay, + ) + + if err != nil { + return deployment.ChangesetOutput{}, err + } + e.Logger.Infow("Proposing offramp dynamic config update", "config", cfg.Updates) + return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ + *p, + }}, nil +} + func isOCR3ConfigSetOnOffRamp( lggr logger.Logger, chain deployment.Chain, diff --git a/deployment/ccip/changeset/cs_chain_contracts_test.go b/deployment/ccip/changeset/cs_chain_contracts_test.go index c50e4d5ee53..ea91f81aeba 100644 --- a/deployment/ccip/changeset/cs_chain_contracts_test.go +++ b/deployment/ccip/changeset/cs_chain_contracts_test.go @@ -14,6 +14,7 @@ import ( "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" + "github.com/smartcontractkit/chainlink/v2/evm/utils" ) func TestUpdateOnRampsDests(t *testing.T) { @@ -307,6 +308,68 @@ func TestUpdateRouterRamps(t *testing.T) { } } +func TestUpdateDynamicConfigOffRampChangeset(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + var mcmsConfig *changeset.MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &changeset.MCMSConfig{ + MinDelay: 0, + } + } + msgInterceptor := utils.RandomAddress() + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateDynamicConfigOffRampChangeset), + Config: changeset.UpdateDynamicConfigOffRampConfig{ + Updates: map[uint64]changeset.OffRampParams{ + source: { + PermissionLessExecutionThresholdSeconds: uint32(2 * 60 * 60), + IsRMNVerificationDisabled: false, + MessageInterceptor: msgInterceptor, + }, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + // Assert the nonce manager configuration is as we expect. + actualConfig, err := state.Chains[source].OffRamp.GetDynamicConfig(nil) + require.NoError(t, err) + require.Equal(t, uint32(2*60*60), actualConfig.PermissionLessExecutionThresholdSeconds) + require.False(t, actualConfig.IsRMNVerificationDisabled) + require.Equal(t, msgInterceptor, actualConfig.MessageInterceptor) + require.Equal(t, state.Chains[source].FeeQuoter.Address(), actualConfig.FeeQuoter) + }) + } +} + func TestUpdateNonceManagersCS(t *testing.T) { for _, tc := range []struct { name string diff --git a/deployment/ccip/changeset/cs_deploy_chain.go b/deployment/ccip/changeset/cs_deploy_chain.go index 408fb4ebd82..a2c761feb1c 100644 --- a/deployment/ccip/changeset/cs_deploy_chain.go +++ b/deployment/ccip/changeset/cs_deploy_chain.go @@ -91,7 +91,7 @@ func (c ChainContractParams) Validate() error { if err := c.FeeQuoterParams.Validate(); err != nil { return fmt.Errorf("invalid FeeQuoterParams: %w", err) } - if err := c.OffRampParams.Validate(); err != nil { + if err := c.OffRampParams.Validate(false); err != nil { return fmt.Errorf("invalid OffRampParams: %w", err) } return nil @@ -145,10 +145,11 @@ type OffRampParams struct { GasForCallExactCheck uint16 PermissionLessExecutionThresholdSeconds uint32 IsRMNVerificationDisabled bool + MessageInterceptor common.Address } -func (c OffRampParams) Validate() error { - if c.GasForCallExactCheck == 0 { +func (c OffRampParams) Validate(ignoreGasForCallExactCheck bool) error { + if !ignoreGasForCallExactCheck && c.GasForCallExactCheck == 0 { return errors.New("GasForCallExactCheck is 0") } if c.PermissionLessExecutionThresholdSeconds == 0 { @@ -496,6 +497,7 @@ func deployChainContractsEVM(e deployment.Environment, chain deployment.Chain, a FeeQuoter: feeQuoterContract.Address(), PermissionLessExecutionThresholdSeconds: contractParams.OffRampParams.PermissionLessExecutionThresholdSeconds, IsRMNVerificationDisabled: contractParams.OffRampParams.IsRMNVerificationDisabled, + MessageInterceptor: contractParams.OffRampParams.MessageInterceptor, }, []offramp.OffRampSourceChainConfigArgs{}, ) From 49c6021474fd936bf9f1c979740d2392359ffdfe Mon Sep 17 00:00:00 2001 From: Margaret Ma Date: Thu, 30 Jan 2025 21:49:28 -0500 Subject: [PATCH 19/43] Add labels to address books (#16148) * add a label to address books * change label from string to set * change metadata to labels * change AsSlice to String on label set and add json tags --- deployment/address_book.go | 88 ++++-- deployment/address_book_labels.go | 67 +++++ deployment/address_book_labels_test.go | 183 ++++++++++++ deployment/address_book_test.go | 262 ++++++++++++++++-- .../changeset/testhelpers/test_helpers.go | 4 +- deployment/common/changeset/internal/mcms.go | 46 ++- .../common/changeset/internal/mcms_test.go | 27 +- deployment/common/changeset/state.go | 44 +-- .../common/proposalutils/mcms_helpers.go | 20 +- deployment/common/types/types.go | 1 + deployment/solana_chain.go | 2 +- 11 files changed, 662 insertions(+), 82 deletions(-) create mode 100644 deployment/address_book_labels.go create mode 100644 deployment/address_book_labels_test.go diff --git a/deployment/address_book.go b/deployment/address_book.go index fde0adc2d97..e123a2116bd 100644 --- a/deployment/address_book.go +++ b/deployment/address_book.go @@ -32,16 +32,36 @@ var ( ) type TypeAndVersion struct { - Type ContractType - Version semver.Version + Type ContractType `json:"type"` + Version semver.Version `json:"version"` + Labels LabelSet `json:"labels,omitempty"` } func (tv TypeAndVersion) String() string { - return fmt.Sprintf("%s %s", tv.Type, tv.Version.String()) + if len(tv.Labels) == 0 { + return fmt.Sprintf("%s %s", tv.Type, tv.Version.String()) + } + + // Use the LabelSet's String method for sorted labels + sortedLabels := tv.Labels.String() + return fmt.Sprintf("%s %s %s", + tv.Type, + tv.Version.String(), + sortedLabels, + ) } func (tv TypeAndVersion) Equal(other TypeAndVersion) bool { - return tv.String() == other.String() + // Compare Type + if tv.Type != other.Type { + return false + } + // Compare Versions + if !tv.Version.Equal(&other.Version) { + return false + } + // Compare Labels + return tv.Labels.Equal(other.Labels) } func MustTypeAndVersionFromString(s string) TypeAndVersion { @@ -55,17 +75,22 @@ func MustTypeAndVersionFromString(s string) TypeAndVersion { // Note this will become useful for validation. When we want // to assert an onchain call to typeAndVersion yields whats expected. func TypeAndVersionFromString(s string) (TypeAndVersion, error) { - parts := strings.Split(s, " ") - if len(parts) != 2 { + parts := strings.Fields(s) // Ignores consecutive spaces + if len(parts) < 2 { return TypeAndVersion{}, fmt.Errorf("invalid type and version string: %s", s) } v, err := semver.NewVersion(parts[1]) if err != nil { return TypeAndVersion{}, err } + labels := make(LabelSet) + if len(parts) > 2 { + labels = NewLabelSet(parts[2:]...) + } return TypeAndVersion{ Type: ContractType(parts[0]), Version: *v, + Labels: labels, }, nil } @@ -73,6 +98,7 @@ func NewTypeAndVersion(t ContractType, v semver.Version) TypeAndVersion { return TypeAndVersion{ Type: t, Version: v, + Labels: make(LabelSet), // empty set, } } @@ -274,25 +300,49 @@ func AddressBookContains(ab AddressBook, chain uint64, addrToFind string) (bool, return false, nil } +type typeVersionKey struct { + Type ContractType + Version string + Labels string // store labels in a canonical form (comma-joined sorted list) +} + +func tvKey(tv TypeAndVersion) typeVersionKey { + sortedLabels := tv.Labels.String() + return typeVersionKey{ + Type: tv.Type, + Version: tv.Version.String(), + Labels: sortedLabels, + } +} + // AddressesContainBundle checks if the addresses // contains a single instance of all the addresses in the bundle. // It returns an error if there are more than one instance of a contract. -func AddressesContainBundle(addrs map[string]TypeAndVersion, wantTypes map[TypeAndVersion]struct{}) (bool, error) { - counts := make(map[TypeAndVersion]int) - for wantType := range wantTypes { - for _, haveType := range addrs { - if wantType == haveType { - counts[wantType]++ - if counts[wantType] > 1 { - return false, fmt.Errorf("found more than one instance of contract %s", wantType) +func AddressesContainBundle(addrs map[string]TypeAndVersion, wantTypes []TypeAndVersion) (bool, error) { + // Count how many times each wanted TypeAndVersion is found + counts := make(map[typeVersionKey]int) + for _, wantTV := range wantTypes { + wantKey := tvKey(wantTV) + for _, haveTV := range addrs { + if wantTV.Equal(haveTV) { + // They match exactly (Type, Version, Labels) + counts[wantKey]++ + if counts[wantKey] > 1 { + return false, fmt.Errorf("found more than one instance of contract %s %s (labels=%s)", + wantTV.Type, wantTV.Version.String(), wantTV.Labels.String()) } } } } - // Either 0 or 1, so we can just check the sum. - sum := 0 - for _, count := range counts { - sum += count + + // Ensure we found *all* wantTypes exactly once + return len(counts) == len(wantTypes), nil +} + +// AddLabel adds a string to the LabelSet in the TypeAndVersion. +func (tv *TypeAndVersion) AddLabel(label string) { + if tv.Labels == nil { + tv.Labels = make(LabelSet) } - return sum == len(wantTypes), nil + tv.Labels.Add(label) } diff --git a/deployment/address_book_labels.go b/deployment/address_book_labels.go new file mode 100644 index 00000000000..f559a39078a --- /dev/null +++ b/deployment/address_book_labels.go @@ -0,0 +1,67 @@ +package deployment + +import ( + "sort" + "strings" +) + +// LabelSet represents a set of labels on an address book entry. +type LabelSet map[string]struct{} + +// NewLabelSet initializes a new LabelSet with any number of labels. +func NewLabelSet(labels ...string) LabelSet { + set := make(LabelSet) + for _, lb := range labels { + set[lb] = struct{}{} + } + return set +} + +// Add inserts a labels into the set. +func (ls LabelSet) Add(labels string) { + ls[labels] = struct{}{} +} + +// Remove deletes a labels from the set, if it exists. +func (ls LabelSet) Remove(labels string) { + delete(ls, labels) +} + +// Contains checks if the set contains the given labels. +func (ls LabelSet) Contains(labels string) bool { + _, ok := ls[labels] + return ok +} + +// String returns the labels as a sorted, space-separated string. +// It implements the fmt.Stringer interface. +func (ls LabelSet) String() string { + if len(ls) == 0 { + return "" + } + + // Collect labels into a slice + labels := make([]string, 0, len(ls)) + for label := range ls { + labels = append(labels, label) + } + + // Sort the labels to ensure consistent ordering + sort.Strings(labels) + + // Concatenate the sorted labels into a single string + return strings.Join(labels, " ") +} + +// Equal checks if two LabelSets are equal. +func (ls LabelSet) Equal(other LabelSet) bool { + if len(ls) != len(other) { + return false + } + for label := range ls { + if _, ok := other[label]; !ok { + return false + } + } + return true +} diff --git a/deployment/address_book_labels_test.go b/deployment/address_book_labels_test.go new file mode 100644 index 00000000000..f42e3568cba --- /dev/null +++ b/deployment/address_book_labels_test.go @@ -0,0 +1,183 @@ +package deployment + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewLabelSet(t *testing.T) { + t.Run("no labels", func(t *testing.T) { + ms := NewLabelSet() + assert.Empty(t, ms, "expected empty set") + }) + + t.Run("some labels", func(t *testing.T) { + ms := NewLabelSet("foo", "bar") + assert.Len(t, ms, 2) + assert.True(t, ms.Contains("foo")) + assert.True(t, ms.Contains("bar")) + assert.False(t, ms.Contains("baz")) + }) +} + +func TestLabelSet_Add(t *testing.T) { + ms := NewLabelSet("initial") + ms.Add("new") + + assert.True(t, ms.Contains("initial"), "expected 'initial' in set") + assert.True(t, ms.Contains("new"), "expected 'new' in set") + assert.Len(t, ms, 2, "expected 2 distinct labels in set") + + // Add duplicate "new" again; size should remain 2 + ms.Add("new") + assert.Len(t, ms, 2, "expected size to remain 2 after adding a duplicate") +} + +func TestLabelSet_Remove(t *testing.T) { + ms := NewLabelSet("remove_me", "keep") + ms.Remove("remove_me") + + assert.False(t, ms.Contains("remove_me"), "expected 'remove_me' to be removed") + assert.True(t, ms.Contains("keep"), "expected 'keep' to remain") + assert.Len(t, ms, 1, "expected set size to be 1 after removal") + + // Removing a non-existent item shouldn't change the size + ms.Remove("non_existent") + assert.Len(t, ms, 1, "expected size to remain 1 after removing a non-existent item") +} + +func TestLabelSet_Contains(t *testing.T) { + ms := NewLabelSet("foo", "bar") + + assert.True(t, ms.Contains("foo")) + assert.True(t, ms.Contains("bar")) + assert.False(t, ms.Contains("baz")) +} + +// TestLabelSet_String tests the String() method of the LabelSet type. +func TestLabelSet_String(t *testing.T) { + tests := []struct { + name string + labels LabelSet + expected string + }{ + { + name: "Empty LabelSet", + labels: NewLabelSet(), + expected: "", + }, + { + name: "Single label", + labels: NewLabelSet("alpha"), + expected: "alpha", + }, + { + name: "Multiple labels in random order", + labels: NewLabelSet("beta", "gamma", "alpha"), + expected: "alpha beta gamma", + }, + { + name: "Labels with special characters", + labels: NewLabelSet("beta", "gamma!", "@alpha"), + expected: "@alpha beta gamma!", + }, + { + name: "Labels with spaces", + labels: NewLabelSet("beta", "gamma delta", "alpha"), + expected: "alpha beta gamma delta", + }, + { + name: "Labels added in different orders", + labels: NewLabelSet("delta", "beta", "alpha"), + expected: "alpha beta delta", + }, + { + name: "Labels with duplicate additions", + labels: NewLabelSet("alpha", "beta", "alpha", "gamma", "beta"), + expected: "alpha beta gamma", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + result := tt.labels.String() + assert.Equal(t, tt.expected, result, "LabelSet.String() should return the expected sorted string") + }) + } +} + +func TestLabelSet_Equal(t *testing.T) { + tests := []struct { + name string + set1 LabelSet + set2 LabelSet + expected bool + }{ + { + name: "Both sets empty", + set1: NewLabelSet(), + set2: NewLabelSet(), + expected: true, + }, + { + name: "First set empty, second set non-empty", + set1: NewLabelSet(), + set2: NewLabelSet("label1"), + expected: false, + }, + { + name: "First set non-empty, second set empty", + set1: NewLabelSet("label1"), + set2: NewLabelSet(), + expected: false, + }, + { + name: "Identical sets with single label", + set1: NewLabelSet("label1"), + set2: NewLabelSet("label1"), + expected: true, + }, + { + name: "Identical sets with multiple labels", + set1: NewLabelSet("label1", "label2", "label3"), + set2: NewLabelSet("label3", "label2", "label1"), // Different order + expected: true, + }, + { + name: "Different sets, same size", + set1: NewLabelSet("label1", "label2", "label3"), + set2: NewLabelSet("label1", "label2", "label4"), + expected: false, + }, + { + name: "Different sets, different sizes", + set1: NewLabelSet("label1", "label2"), + set2: NewLabelSet("label1", "label2", "label3"), + expected: false, + }, + { + name: "Subset sets", + set1: NewLabelSet("label1", "label2"), + set2: NewLabelSet("label1", "label2", "label3"), + expected: false, + }, + { + name: "Disjoint sets", + set1: NewLabelSet("label1", "label2"), + set2: NewLabelSet("label3", "label4"), + expected: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + result := tt.set1.Equal(tt.set2) + assert.Equal(t, tt.expected, result, "Equal(%v, %v) should be %v", tt.set1, tt.set2, tt.expected) + }) + } +} diff --git a/deployment/address_book_test.go b/deployment/address_book_test.go index b1fc358f8c1..0c6b228da2e 100644 --- a/deployment/address_book_test.go +++ b/deployment/address_book_test.go @@ -5,6 +5,7 @@ import ( "sync" "testing" + "github.com/Masterminds/semver/v3" "github.com/ethereum/go-ethereum/common" chainsel "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/assert" @@ -243,35 +244,250 @@ func TestAddressBook_ConcurrencyAndDeadlock(t *testing.T) { wg.Wait() } -func TestAddressesContainsBundle(t *testing.T) { +func TestAddressesContainBundle(t *testing.T) { + t.Parallel() + + // Define some TypeAndVersion values onRamp100 := NewTypeAndVersion("OnRamp", Version1_0_0) onRamp110 := NewTypeAndVersion("OnRamp", Version1_1_0) onRamp120 := NewTypeAndVersion("OnRamp", Version1_2_0) + + // Create one with labels + onRamp100WithLabels := NewTypeAndVersion("OnRamp", Version1_0_0) + onRamp100WithLabels.Labels.Add("sa") + onRamp100WithLabels.Labels.Add("staging") + addr1 := common.HexToAddress("0x1").String() addr2 := common.HexToAddress("0x2").String() addr3 := common.HexToAddress("0x3").String() - // More than one instance should error - _, err := AddressesContainBundle(map[string]TypeAndVersion{ - addr1: onRamp100, - addr2: onRamp100, - }, map[TypeAndVersion]struct{}{onRamp100: {}}) - require.Error(t, err) + tests := []struct { + name string + addrs map[string]TypeAndVersion // input address map + wantTypes []TypeAndVersion // the “bundle” we want + wantErr bool + wantErrMsg string + wantResult bool // expected boolean return when no error + }{ + { + name: "More than one instance => error", + addrs: map[string]TypeAndVersion{ + addr1: onRamp100, + addr2: onRamp100, // duplicate + }, + wantTypes: []TypeAndVersion{onRamp100}, + wantErr: true, + // an example substring check: + wantErrMsg: "found more than one instance of contract", + }, + { + name: "No instance => result false, no error", + addrs: map[string]TypeAndVersion{ + addr1: onRamp110, + addr2: onRamp110, + }, + wantTypes: []TypeAndVersion{onRamp100}, + wantErr: false, + wantResult: false, + }, + { + name: "2 elements => success", + addrs: map[string]TypeAndVersion{ + addr1: onRamp100, + addr2: onRamp110, + addr3: onRamp120, + }, + wantTypes: []TypeAndVersion{onRamp100, onRamp110}, + wantErr: false, + wantResult: true, + }, + { + name: "Mismatched labels => false", + addrs: map[string]TypeAndVersion{ + addr1: onRamp100, // no labels + }, + wantTypes: []TypeAndVersion{onRamp100WithLabels}, + wantErr: false, + wantResult: false, // label mismatch => not found + }, + { + name: "Exact label match => success", + addrs: map[string]TypeAndVersion{ + addr1: onRamp100WithLabels, + }, + wantTypes: []TypeAndVersion{onRamp100WithLabels}, + wantErr: false, + wantResult: true, + }, + { + name: "Duplicate labeled => error", + addrs: map[string]TypeAndVersion{ + addr1: onRamp100WithLabels, + addr2: onRamp100WithLabels, // same type/version/labels => duplicate + }, + wantTypes: []TypeAndVersion{onRamp100WithLabels}, + wantErr: true, + wantErrMsg: "more than one instance of contract", + }, + } - // No such instances should be false - exists, err := AddressesContainBundle(map[string]TypeAndVersion{ - addr2: onRamp110, - addr1: onRamp110, - }, map[TypeAndVersion]struct{}{onRamp100: {}}) - require.NoError(t, err) - assert.Equal(t, exists, false) - - // 2 elements - exists, err = AddressesContainBundle(map[string]TypeAndVersion{ - addr1: onRamp100, - addr2: onRamp110, - addr3: onRamp120, - }, map[TypeAndVersion]struct{}{onRamp100: {}, onRamp110: {}}) - require.NoError(t, err) - assert.Equal(t, exists, true) + for _, tt := range tests { + tt := tt // capture range variable + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + gotResult, gotErr := AddressesContainBundle(tt.addrs, tt.wantTypes) + + if tt.wantErr { + require.Error(t, gotErr, "expected an error but got none") + if tt.wantErrMsg != "" { + require.Contains(t, gotErr.Error(), tt.wantErrMsg) + } + return + } + require.NoError(t, gotErr, "did not expect an error but got one") + assert.Equal(t, tt.wantResult, gotResult, + "expected result %v but got %v", tt.wantResult, gotResult) + }) + } +} + +func TestTypeAndVersionFromString(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input string + wantErr bool + wantType ContractType + wantVersion semver.Version + wantLabels LabelSet + wantTypeAndVersion string + }{ + { + name: "valid - no labels", + input: "CallProxy 1.0.0", + wantErr: false, + wantType: "CallProxy", + wantVersion: Version1_0_0, + wantLabels: NewLabelSet(), + wantTypeAndVersion: "CallProxy 1.0.0", + }, + { + name: "valid - multiple labels, normal spacing", + input: "CallProxy 1.0.0 SA staging", + wantErr: false, + wantType: "CallProxy", + wantVersion: Version1_0_0, + wantLabels: NewLabelSet("SA", "staging"), + wantTypeAndVersion: "CallProxy 1.0.0 SA staging", + }, + { + name: "valid - multiple labels, extra spacing", + input: " CallProxy 1.0.0 SA staging ", + wantErr: false, + wantType: "CallProxy", + wantVersion: Version1_0_0, + wantLabels: NewLabelSet("SA", "staging"), + wantTypeAndVersion: "CallProxy 1.0.0 SA staging", + }, + { + name: "invalid - not enough parts", + input: "CallProxy", + wantErr: true, + }, + { + name: "invalid - version not parseable", + input: "CallProxy notASemver", + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt // capture range variable + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + gotTV, gotErr := TypeAndVersionFromString(tt.input) + if tt.wantErr { + require.Error(t, gotErr, "expected error but got none") + return + } + require.NoError(t, gotErr, "did not expect an error but got one") + + // Check ContractType + require.Equal(t, tt.wantType, gotTV.Type, "incorrect contract type") + + // Check Version + require.Equal(t, tt.wantVersion.String(), gotTV.Version.String(), "incorrect version") + + // Check labels + require.Equal(t, tt.wantLabels, gotTV.Labels, "labels mismatch") + + // Check type and version + require.Equal(t, tt.wantTypeAndVersion, gotTV.String(), "type and version mismatch") + }) + } +} + +func TestTypeAndVersion_AddLabels(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + initialLabels []string + toAdd []string + wantContains []string + wantLen int + }{ + { + name: "add single labels to empty set", + initialLabels: nil, + toAdd: []string{"foo"}, + wantContains: []string{"foo"}, + wantLen: 1, + }, + { + name: "add multiple labels to existing set", + initialLabels: []string{"alpha"}, + toAdd: []string{"beta", "gamma"}, + wantContains: []string{"alpha", "beta", "gamma"}, + wantLen: 3, + }, + { + name: "add duplicate labels", + initialLabels: []string{"dup"}, + toAdd: []string{"dup", "dup", "new"}, + wantContains: []string{"dup", "new"}, + wantLen: 2, + }, + } + + for _, tt := range tests { + tt := tt // capture range variable + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + // Construct a TypeAndVersion with any initial labels + tv := TypeAndVersion{ + Type: "CallProxy", + Version: Version1_0_0, + Labels: NewLabelSet(tt.initialLabels...), + } + + // Call AddLabel for each item in toAdd + for _, label := range tt.toAdd { + tv.AddLabel(label) + } + + // Check final labels length + require.Len(t, tv.Labels, tt.wantLen, "labels size mismatch") + + // Check that expected labels is present + for _, md := range tt.wantContains { + require.True(t, tv.Labels.Contains(md), + "expected labels %q was not found in tv.Labels", md) + } + }) + } } diff --git a/deployment/ccip/changeset/testhelpers/test_helpers.go b/deployment/ccip/changeset/testhelpers/test_helpers.go index 6cd8012936d..0ff3a692d08 100644 --- a/deployment/ccip/changeset/testhelpers/test_helpers.go +++ b/deployment/ccip/changeset/testhelpers/test_helpers.go @@ -988,10 +988,10 @@ func deployTransferTokenOneEnd( return nil, nil, err } for address, v := range chainAddresses { - if deployment.NewTypeAndVersion(changeset.ARMProxy, deployment.Version1_0_0) == v { + if deployment.NewTypeAndVersion(changeset.ARMProxy, deployment.Version1_0_0).Equal(v) { rmnAddress = address } - if deployment.NewTypeAndVersion(changeset.Router, deployment.Version1_2_0) == v { + if deployment.NewTypeAndVersion(changeset.Router, deployment.Version1_2_0).Equal(v) { routerAddress = address } if rmnAddress != "" && routerAddress != "" { diff --git a/deployment/common/changeset/internal/mcms.go b/deployment/common/changeset/internal/mcms.go index 61808e1cbbd..f40d73acc83 100644 --- a/deployment/common/changeset/internal/mcms.go +++ b/deployment/common/changeset/internal/mcms.go @@ -12,12 +12,23 @@ import ( "github.com/smartcontractkit/chainlink/deployment/common/view/v1_0" ) +// DeployMCMSOption is a function that modifies a TypeAndVersion before or after deployment. +type DeployMCMSOption func(*deployment.TypeAndVersion) + +// WithLabel is a functional option that sets a label on the TypeAndVersion. +func WithLabel(label string) DeployMCMSOption { + return func(tv *deployment.TypeAndVersion) { + tv.AddLabel(label) + } +} + func DeployMCMSWithConfig( contractType deployment.ContractType, lggr logger.Logger, chain deployment.Chain, ab deployment.AddressBook, mcmConfig config.Config, + options ...DeployMCMSOption, ) (*deployment.ContractDeploy[*owner_helpers.ManyChainMultiSig], error) { groupQuorums, groupParents, signerAddresses, signerGroups := mcmConfig.ExtractSetConfigInputs() mcm, err := deployment.DeployContract[*owner_helpers.ManyChainMultiSig](lggr, chain, ab, @@ -26,8 +37,14 @@ func DeployMCMSWithConfig( chain.DeployerKey, chain.Client, ) + + tv := deployment.NewTypeAndVersion(contractType, deployment.Version1_0_0) + for _, option := range options { + option(&tv) + } + return deployment.ContractDeploy[*owner_helpers.ManyChainMultiSig]{ - Address: mcmAddr, Contract: mcm, Tx: tx, Tv: deployment.NewTypeAndVersion(contractType, deployment.Version1_0_0), Err: err2, + Address: mcmAddr, Contract: mcm, Tx: tx, Tv: tv, Err: err2, } }) if err != nil { @@ -84,15 +101,20 @@ func DeployMCMSWithTimelockContracts( ab deployment.AddressBook, config types.MCMSWithTimelockConfig, ) (*MCMSWithTimelockDeploy, error) { - bypasser, err := DeployMCMSWithConfig(types.BypasserManyChainMultisig, lggr, chain, ab, config.Bypasser) + opts := []DeployMCMSOption{} + if config.Label != nil { + opts = append(opts, WithLabel(*config.Label)) + } + + bypasser, err := DeployMCMSWithConfig(types.BypasserManyChainMultisig, lggr, chain, ab, config.Bypasser, opts...) if err != nil { return nil, err } - canceller, err := DeployMCMSWithConfig(types.CancellerManyChainMultisig, lggr, chain, ab, config.Canceller) + canceller, err := DeployMCMSWithConfig(types.CancellerManyChainMultisig, lggr, chain, ab, config.Canceller, opts...) if err != nil { return nil, err } - proposer, err := DeployMCMSWithConfig(types.ProposerManyChainMultisig, lggr, chain, ab, config.Proposer) + proposer, err := DeployMCMSWithConfig(types.ProposerManyChainMultisig, lggr, chain, ab, config.Proposer, opts...) if err != nil { return nil, err } @@ -114,8 +136,14 @@ func DeployMCMSWithTimelockContracts( []common.Address{canceller.Address, proposer.Address, bypasser.Address}, // cancellers []common.Address{bypasser.Address}, // bypassers ) + + tv := deployment.NewTypeAndVersion(types.RBACTimelock, deployment.Version1_0_0) + if config.Label != nil { + tv.AddLabel(*config.Label) + } + return deployment.ContractDeploy[*owner_helpers.RBACTimelock]{ - Address: timelock, Contract: cc, Tx: tx2, Tv: deployment.NewTypeAndVersion(types.RBACTimelock, deployment.Version1_0_0), Err: err2, + Address: timelock, Contract: cc, Tx: tx2, Tv: tv, Err: err2, } }) if err != nil { @@ -130,8 +158,14 @@ func DeployMCMSWithTimelockContracts( chain.Client, timelock.Address, ) + + tv := deployment.NewTypeAndVersion(types.CallProxy, deployment.Version1_0_0) + if config.Label != nil { + tv.AddLabel(*config.Label) + } + return deployment.ContractDeploy[*owner_helpers.CallProxy]{ - Address: callProxy, Contract: cc, Tx: tx2, Tv: deployment.NewTypeAndVersion(types.CallProxy, deployment.Version1_0_0), Err: err2, + Address: callProxy, Contract: cc, Tx: tx2, Tv: tv, Err: err2, } }) if err != nil { diff --git a/deployment/common/changeset/internal/mcms_test.go b/deployment/common/changeset/internal/mcms_test.go index 92822422daa..f404a645851 100644 --- a/deployment/common/changeset/internal/mcms_test.go +++ b/deployment/common/changeset/internal/mcms_test.go @@ -18,13 +18,36 @@ import ( func TestDeployMCMSWithConfig(t *testing.T) { lggr := logger.TestLogger(t) + chains, _ := memory.NewMemoryChainsWithChainIDs(t, []uint64{ chainsel.TEST_90000001.EvmChainID, }, 1) ab := deployment.NewMemoryAddressBook() - _, err := internal.DeployMCMSWithConfig(types.ProposerManyChainMultisig, - lggr, chains[chainsel.TEST_90000001.Selector], ab, proposalutils.SingleGroupMCMS(t)) + + // 1) Test WITHOUT a label + mcmNoLabel, err := internal.DeployMCMSWithConfig( + types.ProposerManyChainMultisig, + lggr, + chains[chainsel.TEST_90000001.Selector], + ab, + proposalutils.SingleGroupMCMS(t), + ) + require.NoError(t, err) + require.Empty(t, mcmNoLabel.Tv.Labels, "expected no label to be set") + + // 2) Test WITH a label + label := "SA" + mcmWithLabel, err := internal.DeployMCMSWithConfig( + types.ProposerManyChainMultisig, + lggr, + chains[chainsel.TEST_90000001.Selector], + ab, + proposalutils.SingleGroupMCMS(t), + internal.WithLabel(label), + ) require.NoError(t, err) + require.NotNil(t, mcmWithLabel.Tv.Labels, "expected labels to be set") + require.Contains(t, mcmWithLabel.Tv.Labels, label, "label mismatch") } func TestDeployMCMSWithTimelockContracts(t *testing.T) { diff --git a/deployment/common/changeset/state.go b/deployment/common/changeset/state.go index 0db34abad71..f57686d1d03 100644 --- a/deployment/common/changeset/state.go +++ b/deployment/common/changeset/state.go @@ -95,42 +95,42 @@ func MaybeLoadMCMSWithTimelockChainState(chain deployment.Chain, addresses map[s canceller := deployment.NewTypeAndVersion(types.CancellerManyChainMultisig, deployment.Version1_0_0) bypasser := deployment.NewTypeAndVersion(types.BypasserManyChainMultisig, deployment.Version1_0_0) + // Convert map keys to a slice + wantTypes := []deployment.TypeAndVersion{timelock, proposer, canceller, bypasser, callProxy} + // Ensure we either have the bundle or not. - _, err := deployment.AddressesContainBundle(addresses, - map[deployment.TypeAndVersion]struct{}{ - timelock: {}, proposer: {}, canceller: {}, bypasser: {}, callProxy: {}, - }) + _, err := deployment.AddressesContainBundle(addresses, wantTypes) if err != nil { return nil, fmt.Errorf("unable to check MCMS contracts on chain %s error: %w", chain.Name(), err) } for address, tvStr := range addresses { - switch tvStr { - case timelock: + switch { + case tvStr.Type == timelock.Type && tvStr.Version.String() == timelock.Version.String(): tl, err := owner_helpers.NewRBACTimelock(common.HexToAddress(address), chain.Client) if err != nil { return nil, err } state.Timelock = tl - case callProxy: + case tvStr.Type == callProxy.Type && tvStr.Version.String() == callProxy.Version.String(): cp, err := owner_helpers.NewCallProxy(common.HexToAddress(address), chain.Client) if err != nil { return nil, err } state.CallProxy = cp - case proposer: + case tvStr.Type == proposer.Type && tvStr.Version.String() == proposer.Version.String(): mcms, err := owner_helpers.NewManyChainMultiSig(common.HexToAddress(address), chain.Client) if err != nil { return nil, err } state.ProposerMcm = mcms - case bypasser: + case tvStr.Type == bypasser.Type && tvStr.Version.String() == bypasser.Version.String(): mcms, err := owner_helpers.NewManyChainMultiSig(common.HexToAddress(address), chain.Client) if err != nil { return nil, err } state.BypasserMcm = mcms - case canceller: + case tvStr.Type == canceller.Type && tvStr.Version.String() == canceller.Version.String(): mcms, err := owner_helpers.NewManyChainMultiSig(common.HexToAddress(address), chain.Client) if err != nil { return nil, err @@ -176,14 +176,18 @@ func MaybeLoadLinkTokenState(env deployment.Environment, chainSelectors []uint64 func MaybeLoadLinkTokenChainState(chain deployment.Chain, addresses map[string]deployment.TypeAndVersion) (*LinkTokenState, error) { state := LinkTokenState{} linkToken := deployment.NewTypeAndVersion(types.LinkToken, deployment.Version1_0_0) - // Perhaps revisit if we have a use case for multiple. - _, err := deployment.AddressesContainBundle(addresses, map[deployment.TypeAndVersion]struct{}{linkToken: {}}) + + // Convert map keys to a slice + wantTypes := []deployment.TypeAndVersion{linkToken} + + // Ensure we either have the bundle or not. + _, err := deployment.AddressesContainBundle(addresses, wantTypes) if err != nil { return nil, fmt.Errorf("unable to check link token on chain %s error: %w", chain.Name(), err) } + for address, tvStr := range addresses { - switch tvStr { - case linkToken: + if tvStr.Type == linkToken.Type && tvStr.Version.String() == linkToken.Version.String() { lt, err := link_token.NewLinkToken(common.HexToAddress(address), chain.Client) if err != nil { return nil, err @@ -208,14 +212,18 @@ func (s StaticLinkTokenState) GenerateStaticLinkView() (v1_0.StaticLinkTokenView func MaybeLoadStaticLinkTokenState(chain deployment.Chain, addresses map[string]deployment.TypeAndVersion) (*StaticLinkTokenState, error) { state := StaticLinkTokenState{} staticLinkToken := deployment.NewTypeAndVersion(types.StaticLinkToken, deployment.Version1_0_0) - // Perhaps revisit if we have a use case for multiple. - _, err := deployment.AddressesContainBundle(addresses, map[deployment.TypeAndVersion]struct{}{staticLinkToken: {}}) + + // Convert map keys to a slice + wantTypes := []deployment.TypeAndVersion{staticLinkToken} + + // Ensure we either have the bundle or not. + _, err := deployment.AddressesContainBundle(addresses, wantTypes) if err != nil { return nil, fmt.Errorf("unable to check static link token on chain %s error: %w", chain.Name(), err) } + for address, tvStr := range addresses { - switch tvStr { - case staticLinkToken: + if tvStr.Type == staticLinkToken.Type && tvStr.Version.String() == staticLinkToken.Version.String() { lt, err := link_token_interface.NewLinkToken(common.HexToAddress(address), chain.Client) if err != nil { return nil, err diff --git a/deployment/common/proposalutils/mcms_helpers.go b/deployment/common/proposalutils/mcms_helpers.go index 8b7153e526b..be437479d5e 100644 --- a/deployment/common/proposalutils/mcms_helpers.go +++ b/deployment/common/proposalutils/mcms_helpers.go @@ -229,42 +229,40 @@ func MaybeLoadMCMSWithTimelockContracts(chain deployment.Chain, addresses map[st canceller := deployment.NewTypeAndVersion(types.CancellerManyChainMultisig, deployment.Version1_0_0) bypasser := deployment.NewTypeAndVersion(types.BypasserManyChainMultisig, deployment.Version1_0_0) - // Ensure we either have the bundle or not. - _, err := deployment.AddressesContainBundle(addresses, - map[deployment.TypeAndVersion]struct{}{ - timelock: {}, proposer: {}, canceller: {}, bypasser: {}, callProxy: {}, - }) + // Convert map keys to a slice + wantTypes := []deployment.TypeAndVersion{timelock, proposer, canceller, bypasser, callProxy} + _, err := deployment.AddressesContainBundle(addresses, wantTypes) if err != nil { return nil, fmt.Errorf("unable to check MCMS contracts on chain %s error: %w", chain.Name(), err) } for address, tvStr := range addresses { - switch tvStr { - case timelock: + switch { + case tvStr.Type == timelock.Type && tvStr.Version.String() == timelock.Version.String(): tl, err := owner_helpers.NewRBACTimelock(common.HexToAddress(address), chain.Client) if err != nil { return nil, err } state.Timelock = tl - case callProxy: + case tvStr.Type == callProxy.Type && tvStr.Version.String() == callProxy.Version.String(): cp, err := owner_helpers.NewCallProxy(common.HexToAddress(address), chain.Client) if err != nil { return nil, err } state.CallProxy = cp - case proposer: + case tvStr.Type == proposer.Type && tvStr.Version.String() == proposer.Version.String(): mcms, err := owner_helpers.NewManyChainMultiSig(common.HexToAddress(address), chain.Client) if err != nil { return nil, err } state.ProposerMcm = mcms - case bypasser: + case tvStr.Type == bypasser.Type && tvStr.Version.String() == bypasser.Version.String(): mcms, err := owner_helpers.NewManyChainMultiSig(common.HexToAddress(address), chain.Client) if err != nil { return nil, err } state.BypasserMcm = mcms - case canceller: + case tvStr.Type == canceller.Type && tvStr.Version.String() == canceller.Version.String(): mcms, err := owner_helpers.NewManyChainMultiSig(common.HexToAddress(address), chain.Client) if err != nil { return nil, err diff --git a/deployment/common/types/types.go b/deployment/common/types/types.go index c86fb3e9887..d78ddb0d414 100644 --- a/deployment/common/types/types.go +++ b/deployment/common/types/types.go @@ -33,6 +33,7 @@ type MCMSWithTimelockConfig struct { Bypasser config.Config Proposer config.Config TimelockMinDelay *big.Int + Label *string } type OCRParameters struct { diff --git a/deployment/solana_chain.go b/deployment/solana_chain.go index 0156e5288f7..53d1adce5bb 100644 --- a/deployment/solana_chain.go +++ b/deployment/solana_chain.go @@ -166,7 +166,7 @@ func FindTokenAddress(e Environment, chainSelector uint64, tokenName string) (so tv := NewTypeAndVersion(ContractType(tokenName), Version1_0_0) for address, tvStr := range addresses { - if tvStr == tv { + if tvStr.Equal(tv) { return solana.MustPublicKeyFromBase58(address), nil } } From fe48a3a390e585ea9e6455bde3f483b094552c55 Mon Sep 17 00:00:00 2001 From: Aleksandr Bukata <96521086+bukata-sa@users.noreply.github.com> Date: Fri, 31 Jan 2025 09:40:02 +0000 Subject: [PATCH 20/43] CCIP-4566 token pool views (#16116) * CCIP-4566 token pool views * lint * review fixes * lint * lint --- deployment/ccip/changeset/state.go | 37 ++++ deployment/ccip/view/v1_5_1/token_pool.go | 233 ++++++++++++++++++++++ deployment/ccip/view/view.go | 16 +- 3 files changed, 280 insertions(+), 6 deletions(-) create mode 100644 deployment/ccip/view/v1_5_1/token_pool.go diff --git a/deployment/ccip/changeset/state.go b/deployment/ccip/changeset/state.go index 164bdebd17d..012a4eddf99 100644 --- a/deployment/ccip/changeset/state.go +++ b/deployment/ccip/changeset/state.go @@ -34,6 +34,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_0" "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_2" "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_5" + "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_5_1" "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_6" commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" @@ -184,6 +185,42 @@ func (c CCIPChainState) GenerateView() (view.ChainView, error) { } chainView.TokenAdminRegistry[c.TokenAdminRegistry.Address().Hex()] = taView } + for tokenSymbol, versionToPool := range c.BurnMintTokenPools { + for _, tokenPool := range versionToPool { + tokenPoolView, err := v1_5_1.GenerateTokenPoolView(tokenPool) + if err != nil { + return chainView, errors.Wrapf(err, "failed to generate burn mint token pool view for %s", tokenPool.Address().String()) + } + chainView.BurnMintTokenPool = helpers.AddValueToNestedMap(chainView.BurnMintTokenPool, tokenPool.Address().Hex(), string(tokenSymbol), tokenPoolView) + } + } + for tokenSymbol, versionToPool := range c.BurnWithFromMintTokenPools { + for _, tokenPool := range versionToPool { + tokenPoolView, err := v1_5_1.GenerateTokenPoolView(tokenPool) + if err != nil { + return chainView, errors.Wrapf(err, "failed to generate burn mint token pool view for %s", tokenPool.Address().String()) + } + chainView.BurnMintTokenPool = helpers.AddValueToNestedMap(chainView.BurnMintTokenPool, tokenPool.Address().Hex(), string(tokenSymbol), tokenPoolView) + } + } + for tokenSymbol, versionToPool := range c.BurnFromMintTokenPools { + for _, tokenPool := range versionToPool { + tokenPoolView, err := v1_5_1.GenerateTokenPoolView(tokenPool) + if err != nil { + return chainView, errors.Wrapf(err, "failed to generate burn mint token pool view for %s", tokenPool.Address().String()) + } + chainView.BurnMintTokenPool = helpers.AddValueToNestedMap(chainView.BurnMintTokenPool, tokenPool.Address().Hex(), string(tokenSymbol), tokenPoolView) + } + } + for tokenSymbol, versionToPool := range c.LockReleaseTokenPools { + for _, tokenPool := range versionToPool { + tokenPoolView, err := v1_5_1.GenerateLockReleaseTokenPoolView(tokenPool) + if err != nil { + return chainView, errors.Wrapf(err, "failed to generate lock release token pool view for %s", tokenPool.Address().String()) + } + chainView.LockReleaseTokenPool = helpers.AddValueToNestedMap(chainView.LockReleaseTokenPool, tokenPool.Address().Hex(), string(tokenSymbol), tokenPoolView) + } + } if c.NonceManager != nil { nmView, err := v1_6.GenerateNonceManagerView(c.NonceManager) if err != nil { diff --git a/deployment/ccip/view/v1_5_1/token_pool.go b/deployment/ccip/view/v1_5_1/token_pool.go new file mode 100644 index 00000000000..c782cb1f6cf --- /dev/null +++ b/deployment/ccip/view/v1_5_1/token_pool.go @@ -0,0 +1,233 @@ +package v1_5_1 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "golang.org/x/exp/maps" + + "github.com/smartcontractkit/chainlink/deployment/common/view/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_from_mint_token_pool" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_mint_token_pool" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool" +) + +type TokenPoolContract interface { + Address() common.Address + Owner(opts *bind.CallOpts) (common.Address, error) + TypeAndVersion(*bind.CallOpts) (string, error) + GetToken(opts *bind.CallOpts) (common.Address, error) + GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) + GetRemotePools(opts *bind.CallOpts, remoteChainSelector uint64) ([][]byte, error) + GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) + GetAllowList(opts *bind.CallOpts) ([]common.Address, error) + GetAllowListEnabled(opts *bind.CallOpts) (bool, error) +} + +func GetCurrentInboundRateLimiterState(t TokenPoolContract, remoteChainSelector uint64) (token_pool.RateLimiterTokenBucket, error) { + switch v := t.(type) { + case *burn_mint_token_pool.BurnMintTokenPool: + state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + case *burn_from_mint_token_pool.BurnFromMintTokenPool: + state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + case *burn_with_from_mint_token_pool.BurnWithFromMintTokenPool: + state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + case *lock_release_token_pool.LockReleaseTokenPool: + state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + case *usdc_token_pool.USDCTokenPool: + state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + default: + return token_pool.RateLimiterTokenBucket{}, fmt.Errorf("unknown type %T", t) + } +} + +func GetCurrentOutboundRateLimiterState(t TokenPoolContract, remoteChainSelector uint64) (token_pool.RateLimiterTokenBucket, error) { + switch v := t.(type) { + case *burn_mint_token_pool.BurnMintTokenPool: + state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + case *burn_from_mint_token_pool.BurnFromMintTokenPool: + state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + case *burn_with_from_mint_token_pool.BurnWithFromMintTokenPool: + state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + case *lock_release_token_pool.LockReleaseTokenPool: + state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + case *usdc_token_pool.USDCTokenPool: + state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector) + return token_pool.RateLimiterTokenBucket(state), err + default: + return token_pool.RateLimiterTokenBucket{}, fmt.Errorf("unknown type %T", t) + } +} + +type RemoteChainConfig struct { + // RemoteTokenAddress is the raw representation of the token address on the remote chain. + RemoteTokenAddress []byte + // RemotePoolAddresses are raw addresses of valid token pools on the remote chain. + RemotePoolAddresses [][]byte + // InboundRateLimiterConfig is the rate limiter config for inbound transfers from the remote chain. + InboundRateLimterConfig token_pool.RateLimiterConfig + // OutboundRateLimiterConfig is the rate limiter config for outbound transfers to the remote chain. + OutboundRateLimiterConfig token_pool.RateLimiterConfig +} + +type TokenPoolView struct { + types.ContractMetaData + Token common.Address `json:"token"` + RemoteChainConfigs map[uint64]RemoteChainConfig `json:"remoteChainConfigs"` + AllowList []common.Address `json:"allowList"` + AllowListEnabled bool `json:"allowListEnable"` +} + +type USDCTokenPoolView struct { + TokenPoolView + TokenMessenger common.Address + MessageTransmitter common.Address + LocalDomain uint32 + ChainToDomain map[uint64]usdc_token_pool.USDCTokenPoolDomain +} + +type LockReleaseTokenPoolView struct { + TokenPoolView + AcceptLiquidity bool + Rebalancer common.Address +} + +func GenerateTokenPoolView(pool TokenPoolContract) (TokenPoolView, error) { + owner, err := pool.Owner(nil) + if err != nil { + return TokenPoolView{}, err + } + typeAndVersion, err := pool.TypeAndVersion(nil) + if err != nil { + return TokenPoolView{}, err + } + token, err := pool.GetToken(nil) + if err != nil { + return TokenPoolView{}, err + } + allowList, err := pool.GetAllowList(nil) + if err != nil { + return TokenPoolView{}, err + } + allowListEnabled, err := pool.GetAllowListEnabled(nil) + if err != nil { + return TokenPoolView{}, err + } + remoteChains, err := pool.GetSupportedChains(nil) + if err != nil { + return TokenPoolView{}, err + } + remoteChainConfigs := make(map[uint64]RemoteChainConfig) + for _, remoteChain := range remoteChains { + remotePools, err := pool.GetRemotePools(nil, remoteChain) + if err != nil { + return TokenPoolView{}, err + } + remoteToken, err := pool.GetRemoteToken(nil, remoteChain) + if err != nil { + return TokenPoolView{}, err + } + inboundState, err := GetCurrentInboundRateLimiterState(pool, remoteChain) + if err != nil { + return TokenPoolView{}, err + } + outboundState, err := GetCurrentOutboundRateLimiterState(pool, remoteChain) + if err != nil { + return TokenPoolView{}, err + } + remoteChainConfigs[remoteChain] = RemoteChainConfig{ + RemoteTokenAddress: remoteToken, + RemotePoolAddresses: remotePools, + InboundRateLimterConfig: token_pool.RateLimiterConfig{ + IsEnabled: inboundState.IsEnabled, + Capacity: inboundState.Capacity, + Rate: inboundState.Rate, + }, + OutboundRateLimiterConfig: token_pool.RateLimiterConfig{ + IsEnabled: outboundState.IsEnabled, + Capacity: outboundState.Capacity, + Rate: outboundState.Rate, + }, + } + } + + return TokenPoolView{ + ContractMetaData: types.ContractMetaData{ + TypeAndVersion: typeAndVersion, + Address: pool.Address(), + Owner: owner, + }, + Token: token, + RemoteChainConfigs: remoteChainConfigs, + AllowList: allowList, + AllowListEnabled: allowListEnabled, + }, nil +} + +func GenerateLockReleaseTokenPoolView(pool *lock_release_token_pool.LockReleaseTokenPool) (LockReleaseTokenPoolView, error) { + basePoolView, err := GenerateTokenPoolView(pool) + if err != nil { + return LockReleaseTokenPoolView{}, err + } + acceptLiquidity, err := pool.CanAcceptLiquidity(nil) + if err != nil { + return LockReleaseTokenPoolView{}, err + } + rebalancer, err := pool.GetRebalancer(nil) + if err != nil { + return LockReleaseTokenPoolView{}, err + } + return LockReleaseTokenPoolView{ + TokenPoolView: basePoolView, + AcceptLiquidity: acceptLiquidity, + Rebalancer: rebalancer, + }, nil +} + +func GenerateUSDCTokenPoolView(pool *usdc_token_pool.USDCTokenPool) (USDCTokenPoolView, error) { + basePoolView, err := GenerateTokenPoolView(pool) + if err != nil { + return USDCTokenPoolView{}, err + } + tokenMessenger, err := pool.ITokenMessenger(nil) + if err != nil { + return USDCTokenPoolView{}, err + } + messageTransmitter, err := pool.IMessageTransmitter(nil) + if err != nil { + return USDCTokenPoolView{}, err + } + localDomain, err := pool.ILocalDomainIdentifier(nil) + if err != nil { + return USDCTokenPoolView{}, err + } + chainToDomain := make(map[uint64]usdc_token_pool.USDCTokenPoolDomain) + remoteChains := maps.Keys(basePoolView.RemoteChainConfigs) + for _, chainSel := range remoteChains { + domain, err := pool.GetDomain(nil, chainSel) + if err != nil { + return USDCTokenPoolView{}, err + } + chainToDomain[chainSel] = domain + } + return USDCTokenPoolView{ + TokenPoolView: basePoolView, + TokenMessenger: tokenMessenger, + MessageTransmitter: messageTransmitter, + LocalDomain: localDomain, + ChainToDomain: chainToDomain, + }, nil +} diff --git a/deployment/ccip/view/view.go b/deployment/ccip/view/view.go index 8f698ba2277..7c35142ee5f 100644 --- a/deployment/ccip/view/view.go +++ b/deployment/ccip/view/view.go @@ -6,6 +6,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_0" "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_2" "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_5" + "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_5_1" "github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_6" "github.com/smartcontractkit/chainlink/deployment/common/view" common_v1_0 "github.com/smartcontractkit/chainlink/deployment/common/view/v1_0" @@ -17,12 +18,15 @@ type ChainView struct { // v1.2 Router map[string]v1_2.RouterView `json:"router,omitempty"` // v1.5 - TokenAdminRegistry map[string]v1_5.TokenAdminRegistryView `json:"tokenAdminRegistry,omitempty"` - CommitStore map[string]v1_5.CommitStoreView `json:"commitStore,omitempty"` - PriceRegistry map[string]v1_2.PriceRegistryView `json:"priceRegistry,omitempty"` - EVM2EVMOnRamp map[string]v1_5.OnRampView `json:"evm2evmOnRamp,omitempty"` - EVM2EVMOffRamp map[string]v1_5.OffRampView `json:"evm2evmOffRamp,omitempty"` - RMN map[string]v1_5.RMNView `json:"rmn,omitempty"` + TokenAdminRegistry map[string]v1_5.TokenAdminRegistryView `json:"tokenAdminRegistry,omitempty"` + BurnMintTokenPool map[string]map[string]v1_5_1.TokenPoolView `json:"burnMintTokenPool,omitempty"` + LockReleaseTokenPool map[string]map[string]v1_5_1.LockReleaseTokenPoolView `json:"lockReleaseTokenPool,omitempty"` + USDCTokenPool map[string]map[string]v1_5_1.USDCTokenPoolView `json:"usdcTokenPool,omitempty"` + CommitStore map[string]v1_5.CommitStoreView `json:"commitStore,omitempty"` + PriceRegistry map[string]v1_2.PriceRegistryView `json:"priceRegistry,omitempty"` + EVM2EVMOnRamp map[string]v1_5.OnRampView `json:"evm2evmOnRamp,omitempty"` + EVM2EVMOffRamp map[string]v1_5.OffRampView `json:"evm2evmOffRamp,omitempty"` + RMN map[string]v1_5.RMNView `json:"rmn,omitempty"` // v1.6 FeeQuoter map[string]v1_6.FeeQuoterView `json:"feeQuoter,omitempty"` From 638de2944efad3de98d2873a413be250101d6790 Mon Sep 17 00:00:00 2001 From: joaoluisam Date: Fri, 31 Jan 2025 09:49:09 +0000 Subject: [PATCH 21/43] INTAUTO-306 Add ccip message assertions e2e tests (#16107) * Add ccip message received assertion * lint fixes * lint fix * fix unecessary string conversion * change set and fixes * update gas snapshot * Add function comments * address pr comments * update snapshot and add minor validation * add msg data validation --- contracts/.changeset/smart-bats-repair.md | 5 + contracts/gas-snapshots/ccip.gas-snapshot | 88 ++--- .../receivers/MaybeRevertMessageReceiver.sol | 71 +++- .../maybe_revert_message_receiver.go | 368 +++++++++++++++++- ...rapper-dependency-versions-do-not-edit.txt | 2 +- .../ccip-tests/actions/ccip_helpers.go | 147 ++++++- .../ccip-tests/contracts/contract_models.go | 13 + integration-tests/ccip-tests/load/helper.go | 2 +- .../ccip-tests/smoke/ccip_test.go | 20 +- 9 files changed, 630 insertions(+), 86 deletions(-) create mode 100644 contracts/.changeset/smart-bats-repair.md diff --git a/contracts/.changeset/smart-bats-repair.md b/contracts/.changeset/smart-bats-repair.md new file mode 100644 index 00000000000..220880ef2b1 --- /dev/null +++ b/contracts/.changeset/smart-bats-repair.md @@ -0,0 +1,5 @@ +--- +'@chainlink/contracts': patch +--- + +Update mayberevertmessagereceiver contract to emit message received event and allow token withdrawal diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index 190f834c353..7e99289b08c 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -27,8 +27,8 @@ CCIPHome_setCandidate:test_setCandidate() (gas: 1365392) CCIPHome_supportsInterface:test_supportsInterface() (gas: 9885) DefensiveExampleTest:test_HappyPath() (gas: 200535) DefensiveExampleTest:test_Recovery() (gas: 424996) -E2E:test_E2E_3MessagesMMultiOffRampSuccess_gas() (gas: 1495937) -ERC165CheckerReverting_supportsInterfaceReverting:test__supportsInterfaceReverting() (gas: 10445) +E2E:test_E2E_3MessagesMMultiOffRampSuccess_gas() (gas: 1514547) +ERC165CheckerReverting_supportsInterfaceReverting:test__supportsInterfaceReverting() (gas: 10517) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_fallbackToWethTransfer() (gas: 96964) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_happyPath() (gas: 49797) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_wrongToken() (gas: 17460) @@ -203,11 +203,11 @@ NonceManager_applyPreviousRampsUpdates:test_MultipleRampsUpdates() (gas: 123617) NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySet_overrideAllowed() (gas: 45935) NonceManager_applyPreviousRampsUpdates:test_SingleRampUpdate() (gas: 66937) NonceManager_applyPreviousRampsUpdates:test_ZeroInput() (gas: 12123) -NonceManager_getInboundNonce:test_getInboundNonce_NoPrevOffRampForChain() (gas: 179167) -NonceManager_getInboundNonce:test_getInboundNonce_Upgraded() (gas: 146356) -NonceManager_getInboundNonce:test_getInboundNonce_UpgradedNonceNewSenderStartsAtZero() (gas: 182637) -NonceManager_getInboundNonce:test_getInboundNonce_UpgradedNonceStartsAtV1Nonce() (gas: 245611) -NonceManager_getInboundNonce:test_getInboundNonce_UpgradedOffRampNonceSkipsIfMsgInFlight() (gas: 214256) +NonceManager_getInboundNonce:test_getInboundNonce_NoPrevOffRampForChain() (gas: 183777) +NonceManager_getInboundNonce:test_getInboundNonce_Upgraded() (gas: 150965) +NonceManager_getInboundNonce:test_getInboundNonce_UpgradedNonceNewSenderStartsAtZero() (gas: 187248) +NonceManager_getInboundNonce:test_getInboundNonce_UpgradedNonceStartsAtV1Nonce() (gas: 254856) +NonceManager_getInboundNonce:test_getInboundNonce_UpgradedOffRampNonceSkipsIfMsgInFlight() (gas: 218870) NonceManager_getInboundNonce:test_getInboundNonce_UpgradedSenderNoncesReadsPreviousRamp() (gas: 60418) NonceManager_getIncrementedOutboundNonce:test_getIncrementedOutboundNonce() (gas: 37974) NonceManager_getIncrementedOutboundNonce:test_incrementInboundNonce() (gas: 38746) @@ -225,12 +225,12 @@ OffRamp_applySourceChainConfigUpdates:test_ApplyZeroUpdates() (gas: 16671) OffRamp_applySourceChainConfigUpdates:test_ReplaceExistingChain() (gas: 180998) OffRamp_applySourceChainConfigUpdates:test_ReplaceExistingChainOnRamp() (gas: 168513) OffRamp_applySourceChainConfigUpdates:test_allowNonOnRampUpdateAfterLaneIsUsed() (gas: 284861) -OffRamp_batchExecute:test_MultipleReportsDifferentChains() (gas: 326824) -OffRamp_batchExecute:test_MultipleReportsDifferentChainsSkipCursedChain() (gas: 171115) -OffRamp_batchExecute:test_MultipleReportsSameChain() (gas: 270123) -OffRamp_batchExecute:test_MultipleReportsSkipDuplicate() (gas: 162336) -OffRamp_batchExecute:test_SingleReport() (gas: 149878) -OffRamp_batchExecute:test_Unhealthy() (gas: 533860) +OffRamp_batchExecute:test_MultipleReportsDifferentChains() (gas: 340742) +OffRamp_batchExecute:test_MultipleReportsDifferentChainsSkipCursedChain() (gas: 175741) +OffRamp_batchExecute:test_MultipleReportsSameChain() (gas: 284041) +OffRamp_batchExecute:test_MultipleReportsSkipDuplicate() (gas: 166949) +OffRamp_batchExecute:test_SingleReport() (gas: 154488) +OffRamp_batchExecute:test_Unhealthy() (gas: 546735) OffRamp_commit:test_OnlyGasPriceUpdates() (gas: 112995) OffRamp_commit:test_OnlyTokenPriceUpdates() (gas: 112949) OffRamp_commit:test_PriceSequenceNumberCleared() (gas: 355405) @@ -240,52 +240,52 @@ OffRamp_commit:test_RootWithRMNDisabled() (gas: 153873) OffRamp_commit:test_StaleReportWithRoot() (gas: 232057) OffRamp_commit:test_ValidPriceUpdateThenStaleReportWithRoot() (gas: 206722) OffRamp_constructor:test_Constructor() (gas: 6340113) -OffRamp_execute:test_LargeBatch() (gas: 3383493) -OffRamp_execute:test_MultipleReports() (gas: 292253) -OffRamp_execute:test_MultipleReportsWithPartialValidationFailures() (gas: 365622) -OffRamp_execute:test_SingleReport() (gas: 169111) -OffRamp_executeSingleMessage:test_executeSingleMessage_NoTokens() (gas: 51610) +OffRamp_execute:test_LargeBatch() (gas: 3537781) +OffRamp_execute:test_MultipleReports() (gas: 306193) +OffRamp_execute:test_MultipleReportsWithPartialValidationFailures() (gas: 370270) +OffRamp_execute:test_SingleReport() (gas: 173724) +OffRamp_executeSingleMessage:test_executeSingleMessage_NoTokens() (gas: 55443) OffRamp_executeSingleMessage:test_executeSingleMessage_NonContract() (gas: 20514) OffRamp_executeSingleMessage:test_executeSingleMessage_NonContractWithTokens() (gas: 230418) -OffRamp_executeSingleMessage:test_executeSingleMessage_WithMessageInterceptor() (gas: 87465) -OffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens() (gas: 259935) -OffRamp_executeSingleReport:test_InvalidSourcePoolAddress() (gas: 455918) -OffRamp_executeSingleReport:test_ReceiverError() (gas: 181083) -OffRamp_executeSingleReport:test_SingleMessageNoTokens() (gas: 205792) -OffRamp_executeSingleReport:test_SingleMessageNoTokensOtherChain() (gas: 241879) -OffRamp_executeSingleReport:test_SingleMessageNoTokensUnordered() (gas: 185785) +OffRamp_executeSingleMessage:test_executeSingleMessage_WithMessageInterceptor() (gas: 91298) +OffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens() (gas: 265210) +OffRamp_executeSingleReport:test_InvalidSourcePoolAddress() (gas: 462329) +OffRamp_executeSingleReport:test_ReceiverError() (gas: 181094) +OffRamp_executeSingleReport:test_SingleMessageNoTokens() (gas: 215033) +OffRamp_executeSingleReport:test_SingleMessageNoTokensOtherChain() (gas: 249545) +OffRamp_executeSingleReport:test_SingleMessageNoTokensUnordered() (gas: 195030) OffRamp_executeSingleReport:test_SingleMessageToNonCCIPReceiver() (gas: 244181) -OffRamp_executeSingleReport:test_SingleMessagesNoTokensSuccess_gas() (gas: 134917) +OffRamp_executeSingleReport:test_SingleMessagesNoTokensSuccess_gas() (gas: 139526) OffRamp_executeSingleReport:test_SkippedIncorrectNonce() (gas: 58558) -OffRamp_executeSingleReport:test_SkippedIncorrectNonceStillExecutes() (gas: 392884) -OffRamp_executeSingleReport:test_TwoMessagesWithTokensAndGE() (gas: 562962) -OffRamp_executeSingleReport:test_TwoMessagesWithTokensSuccess_gas() (gas: 511342) -OffRamp_executeSingleReport:test_Unhealthy() (gas: 529483) -OffRamp_executeSingleReport:test_WithCurseOnAnotherSourceChain() (gas: 439833) -OffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessage() (gas: 158559) -OffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessageUnordered() (gas: 128943) +OffRamp_executeSingleReport:test_SkippedIncorrectNonceStillExecutes() (gas: 399284) +OffRamp_executeSingleReport:test_TwoMessagesWithTokensAndGE() (gas: 575811) +OffRamp_executeSingleReport:test_TwoMessagesWithTokensSuccess_gas() (gas: 524188) +OffRamp_executeSingleReport:test_Unhealthy() (gas: 542355) +OffRamp_executeSingleReport:test_WithCurseOnAnotherSourceChain() (gas: 450383) +OffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessage() (gas: 163171) +OffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessageUnordered() (gas: 133556) OffRamp_getExecutionState:test_FillExecutionState() (gas: 3955662) OffRamp_getExecutionState:test_GetDifferentChainExecutionState() (gas: 121311) OffRamp_getExecutionState:test_GetExecutionState() (gas: 90102) -OffRamp_manuallyExecute:test_manuallyExecute() (gas: 212915) -OffRamp_manuallyExecute:test_manuallyExecute_DoesNotRevertIfUntouched() (gas: 166028) +OffRamp_manuallyExecute:test_manuallyExecute() (gas: 212742) +OffRamp_manuallyExecute:test_manuallyExecute_DoesNotRevertIfUntouched() (gas: 166042) OffRamp_manuallyExecute:test_manuallyExecute_LowGasLimit() (gas: 479692) OffRamp_manuallyExecute:test_manuallyExecute_ReentrancyFails() (gas: 2230185) -OffRamp_manuallyExecute:test_manuallyExecute_WithGasOverride() (gas: 213465) -OffRamp_manuallyExecute:test_manuallyExecute_WithMultiReportGasOverride() (gas: 735042) -OffRamp_manuallyExecute:test_manuallyExecute_WithPartialMessages() (gas: 338095) +OffRamp_manuallyExecute:test_manuallyExecute_WithGasOverride() (gas: 213292) +OffRamp_manuallyExecute:test_manuallyExecute_WithMultiReportGasOverride() (gas: 753781) +OffRamp_manuallyExecute:test_manuallyExecute_WithPartialMessages() (gas: 347264) OffRamp_releaseOrMintSingleToken:test__releaseOrMintSingleToken() (gas: 94629) OffRamp_releaseOrMintTokens:test_releaseOrMintTokens() (gas: 161157) OffRamp_releaseOrMintTokens:test_releaseOrMintTokens_WithGasOverride() (gas: 163023) OffRamp_releaseOrMintTokens:test_releaseOrMintTokens_destDenominatedDecimals() (gas: 174276) OffRamp_setDynamicConfig:test_SetDynamicConfig() (gas: 25442) OffRamp_setDynamicConfig:test_SetDynamicConfigWithInterceptor() (gas: 47493) -OffRamp_trialExecute:test_trialExecute() (gas: 263680) +OffRamp_trialExecute:test_trialExecute() (gas: 268955) OffRamp_trialExecute:test_trialExecute_RateLimitError() (gas: 120710) OffRamp_trialExecute:test_trialExecute_RevertsWhen_SenderIsGasEstimator_InsufficientGasForToCompleteTx() (gas: 67132) OffRamp_trialExecute:test_trialExecute_SenderIsNotGasEstimator_CallWithExactGasReverts() (gas: 24573) OffRamp_trialExecute:test_trialExecute_TokenHandlingErrorIsCaught() (gas: 131998) -OffRamp_trialExecute:test_trialExecute_TokenPoolIsNotAContract() (gas: 281305) +OffRamp_trialExecute:test_trialExecute_TokenPoolIsNotAContract() (gas: 286580) OnRampTokenPoolReentrancy:test_OnRampTokenPoolReentrancy() (gas: 245211) OnRampWithMessageTransformer_executeSingleMessage:test_forwardFromRouter() (gas: 122477) OnRampWithMessageTransformer_setMessageTransformer:test_setMessageTransformer() (gas: 701204) @@ -342,7 +342,7 @@ RateLimiter_setTokenBucketConfig:test_SetRateLimiterConfig() (gas: 38645) RegistryModuleOwnerCustom_registerAccessControlDefaultAdmin:test_registerAccessControlDefaultAdmin() (gas: 130641) RegistryModuleOwnerCustom_registerAdminViaGetCCIPAdmin:test_registerAdminViaGetCCIPAdmin() (gas: 130136) RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner() (gas: 129941) -Router_applyRampUpdates:test_applyRampUpdates_OffRampUpdatesWithRouting() (gas: 10413055) +Router_applyRampUpdates:test_applyRampUpdates_OffRampUpdatesWithRouting() (gas: 10864375) Router_applyRampUpdates:test_applyRampUpdates_OnRampDisable() (gas: 56445) Router_ccipSend:test_CCIPSendLinkFeeNoTokenSuccess_gas() (gas: 126090) Router_ccipSend:test_CCIPSendLinkFeeOneTokenSuccess_gas() (gas: 213515) @@ -359,9 +359,9 @@ Router_constructor:test_Constructor() (gas: 13170) Router_getArmProxy:test_getArmProxy() (gas: 10573) Router_getFee:test_GetFeeSupportedChain() (gas: 52367) 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) +Router_routeMessage:test_routeMessage_AutoExec() (gas: 41832) +Router_routeMessage:test_routeMessage_ExecutionEvent() (gas: 157232) +Router_routeMessage:test_routeMessage_ManualExec() (gas: 34881) SiloedLockReleaseTokenPool_lockOrBurn:test_lockOrBurn_SiloedFunds() (gas: 76874) SiloedLockReleaseTokenPool_lockOrBurn:test_lockOrBurn_UnsiloedFunds() (gas: 76104) SiloedLockReleaseTokenPool_provideLiqudity:test_ProvideLiquidity_LegacyProvideLiquiditySelector() (gas: 91873) diff --git a/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol b/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol index 91a697ac318..8352a84853e 100644 --- a/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol +++ b/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol @@ -1,29 +1,43 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/IERC20.sol"; +import {IERC165} from "../../../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol"; import {IAny2EVMMessageReceiver} from "../../../interfaces/IAny2EVMMessageReceiver.sol"; import {Client} from "../../../libraries/Client.sol"; -import {IERC165} from "../../../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol"; - contract MaybeRevertMessageReceiver is IAny2EVMMessageReceiver, IERC165 { error ReceiveRevert(); error CustomError(bytes err); + error Unauthorized(); + error InsufficientBalance(uint256 available, uint256 required); + error TransferFailed(); event ValueReceived(uint256 amount); - event MessageReceived(); + event NativeFundsWithdrawn(address indexed owner, uint256 amount); + event TokensWithdrawn(address indexed token, address indexed owner, uint256 amount); + event MessageReceived( + bytes32 messageId, uint64 sourceChainSelector, bytes sender, bytes data, Client.EVMTokenAmount[] destTokenAmounts + ); - address private s_manager; + address private immutable i_manager; bool public s_toRevert; bytes private s_err; constructor( bool toRevert ) { - s_manager = msg.sender; + i_manager = msg.sender; s_toRevert = toRevert; } + modifier onlyManager() { + if (msg.sender != i_manager) { + revert Unauthorized(); + } + _; + } + function setRevert( bool toRevert ) external { @@ -46,12 +60,15 @@ contract MaybeRevertMessageReceiver is IAny2EVMMessageReceiver, IERC165 { } function ccipReceive( - Client.Any2EVMMessage calldata + Client.Any2EVMMessage calldata message ) external override { if (s_toRevert) { revert CustomError(s_err); } - emit MessageReceived(); + + emit MessageReceived( + message.messageId, message.sourceChainSelector, message.sender, message.data, message.destTokenAmounts + ); } // solhint-disable-next-line no-complex-fallback @@ -62,4 +79,44 @@ contract MaybeRevertMessageReceiver is IAny2EVMMessageReceiver, IERC165 { emit ValueReceived(msg.value); } + + /// @notice Allows the manager (deployer) to withdraw all Ether from the contract + function withdrawFunds() external onlyManager { + uint256 balance = address(this).balance; + + (bool success,) = i_manager.call{value: balance}(""); + if (!success) { + revert TransferFailed(); + } + + emit NativeFundsWithdrawn(i_manager, balance); + } + + /// @notice Allows the manager to withdraw ERC-20 tokens from the contract + /// @param token The address of the ERC-20 token contract + /// @param amount The amount of tokens to withdraw + function withdrawTokens(address token, uint256 amount) external onlyManager { + IERC20 erc20 = IERC20(token); + uint256 balance = erc20.balanceOf(address(this)); + if (balance < amount) { + revert InsufficientBalance(balance, amount); + } + + bool success = erc20.transfer(i_manager, amount); + if (!success) { + revert TransferFailed(); + } + + emit TokensWithdrawn(token, i_manager, amount); + } + + /// @notice Fetches the balance of an ERC-20 token held by the contract + /// @param token The address of the ERC-20 token contract + /// @return The balance of the specified ERC-20 token + function balanceOfToken( + address token + ) external view returns (uint256) { + IERC20 erc20 = IERC20(token); + return erc20.balanceOf(address(this)); + } } diff --git a/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go b/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go index 8d3c36757aa..8f7b15cd5e4 100644 --- a/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go +++ b/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go @@ -44,8 +44,8 @@ type ClientEVMTokenAmount struct { } var MaybeRevertMessageReceiverMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"toRevert\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"ccipReceive\",\"inputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structClient.Any2EVMMessage\",\"components\":[{\"name\":\"messageId\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"sourceChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"sender\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\",\"internalType\":\"structClient.EVMTokenAmount[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"s_toRevert\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setErr\",\"inputs\":[{\"name\":\"err\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRevert\",\"inputs\":[{\"name\":\"toRevert\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"pure\"},{\"type\":\"event\",\"name\":\"MessageReceived\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValueReceived\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CustomError\",\"inputs\":[{\"name\":\"err\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"ReceiveRevert\",\"inputs\":[]}]", - Bin: "0x608034607d57601f6107a838819003918201601f19168301916001600160401b03831184841017608257808492602094604052833981010312607d5751801515809103607d57600080546001600160a81b0319163360ff60a01b19161760a09290921b60ff60a01b1691909117905560405161070f90816100998239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561007e575b50361561001b57600080fd5b60ff60005460a01c16610054577fe12e3b7047ff60a2dd763cf536a43597e5ce7fe7aa7476345bd4cd079912bcef6020604051348152a1005b7f3085b8db0000000000000000000000000000000000000000000000000000000060005260046000fd5b60003560e01c90816301ffc9a7146105f3575080635100fc21146105af57806377f5b0e6146102da57806385572ffb1461014d57638fb5f171146100c2573861000f565b346101485760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014857600435801515809103610148577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff00000000000000000000000000000000000000006000549260a01b16911617600055600080f35b600080fd5b346101485760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101485760043567ffffffffffffffff8111610148577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a091360301126101485760ff60005460a01c166101ee577fd82ce31e3523f6eeb2d24317b2b4133001e8472729657f663b68624c45f8f3e8600080a1005b6040517f5a4ff6710000000000000000000000000000000000000000000000000000000081526020600482015280600060015461022a816106af565b908160248501526001811690816000146102a2575060011461024b57500390fd5b6001600090815291507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b81831061028857505081010360440190fd5b805460448487010152849350602090920191600101610276565b604493507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201010390fd5b346101485760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101485760043567ffffffffffffffff8111610148573660238201121561014857806004013567ffffffffffffffff811161058057604051917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f8501160116830183811067ffffffffffffffff82111761058057604052818352366024838301011161014857816000926024602093018386013783010152805167ffffffffffffffff8111610580576103be6001546106af565b601f81116104dd575b50602091601f821160011461042357918192600092610418575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c191617600155600080f35b0151905082806103e1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169260016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69160005b8581106104c55750836001951061048e575b505050811b01600155005b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c19169055828080610483565b91926020600181928685015181550194019201610471565b6001600052601f820160051c7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6019060208310610558575b601f0160051c7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601905b81811061054c57506103c7565b6000815560010161053f565b7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69150610515565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b346101485760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014857602060ff60005460a01c166040519015158152f35b346101485760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014857600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361014857817f85572ffb0000000000000000000000000000000000000000000000000000000060209314908115610685575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150148361067e565b90600182811c921680156106f8575b60208310146106c957565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f16916106be56fea164736f6c634300081a000a", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"toRevert\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"balanceOfToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ccipReceive\",\"inputs\":[{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structClient.Any2EVMMessage\",\"components\":[{\"name\":\"messageId\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"sourceChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"sender\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\",\"internalType\":\"structClient.EVMTokenAmount[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"s_toRevert\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setErr\",\"inputs\":[{\"name\":\"err\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRevert\",\"inputs\":[{\"name\":\"toRevert\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"withdrawFunds\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawTokens\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"MessageReceived\",\"inputs\":[{\"name\":\"messageId\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"sourceChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"sender\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"data\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\",\"indexed\":false,\"internalType\":\"structClient.EVMTokenAmount[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NativeFundsWithdrawn\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokensWithdrawn\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValueReceived\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CustomError\",\"inputs\":[{\"name\":\"err\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"InsufficientBalance\",\"inputs\":[{\"name\":\"available\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"required\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ReceiveRevert\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TransferFailed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[]}]", + Bin: "0x60a034607657601f610dbb38819003918201601f19168301916001600160401b03831184841017607b57808492602094604052833981010312607657518015158091036076573360805260ff801960005416911617600055604051610d29908161009282396080518181816107e301526109300152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561007b575b50361561001b57600080fd5b60ff60005416610051577fe12e3b7047ff60a2dd763cf536a43597e5ce7fe7aa7476345bd4cd079912bcef6020604051348152a1005b7f3085b8db0000000000000000000000000000000000000000000000000000000060005260046000fd5b60003560e01c90816301ffc9a714610adf5750806306b091f9146108df57806324600fc3146107b25780635100fc211461077157806377f5b0e6146104db57806385572ffb1461022e5780638fb5f171146101c05763b99152d0146100e0573861000f565b346101a75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a7576024602073ffffffffffffffffffffffffffffffffffffffff610130610b9b565b16604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa80156101b45760009061017c575b602090604051908152f35b506020813d6020116101ac575b8161019660209383610bbe565b810103126101a75760209051610171565b600080fd5b3d9150610189565b6040513d6000823e3d90fd5b346101a75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a7576004358015158091036101a75760ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005416911617600055600080f35b346101a75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a75760043567ffffffffffffffff81116101a7578060040181360360a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101a75760ff600054166103ef5760248301359267ffffffffffffffff84168094036101a7576102cf6044820184610c8c565b90916102de6064820186610c8c565b9490917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd608482013592018212156101a757019360048501359467ffffffffffffffff86116101a757602401968560061b360388136101a75760209461036c9461035e9260405199358a52878a015260a060408a015260a0890191610cdd565b918683036060880152610cdd565b83810360808501528281520192906000905b8082106103ad577f707732b700184c0ab3b799f43f03de9b3606a144cfb367f98291044e71972cdc84860385a1005b90919384359073ffffffffffffffffffffffffffffffffffffffff82168092036101a7576040816001938293526020880135602082015201950192019061037e565b6040517f5a4ff6710000000000000000000000000000000000000000000000000000000081526020600482015280600060015461042b81610c39565b908160248501526001811690816000146104a3575060011461044c57500390fd5b6001600090815291507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b81831061048957505081010360440190fd5b805460448487010152849350602090920191600101610477565b604493507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201010390fd5b346101a75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a75760043567ffffffffffffffff81116101a757366023820112156101a757806004013561053581610bff565b916105436040519384610bbe565b81835236602483830101116101a757816000926024602093018386013783010152805167ffffffffffffffff811161074257610580600154610c39565b601f811161069f575b50602091601f82116001146105e5579181926000926105da575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c191617600155600080f35b0151905082806105a3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169260016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69160005b85811061068757508360019510610650575b505050811b01600155005b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c19169055828080610645565b91926020600181928685015181550194019201610633565b6001600052601f820160051c7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601906020831061071a575b601f0160051c7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601905b81811061070e5750610589565b60008155600101610701565b7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf691506106d7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b346101a75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a757602060ff600054166040519015158152f35b346101a75760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a7577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8116908133036108b55760008080804780955af13d156108b0573d61083b81610bff565b906108496040519283610bbe565b8152600060203d92013e5b156108865760207fd50b71a2790ecccf5881141fe9ae079e17c66aace5d50ba383d443ecd398ffa591604051908152a2005b7f90b8ec180000000000000000000000000000000000000000000000000000000060005260046000fd5b610854565b7f82b429000000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a75760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a757610916610b9b565b60243573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016918233036108b55773ffffffffffffffffffffffffffffffffffffffff16906040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481865afa9081156101b457600091610aad575b50818110610a7d57506040517fa9059cbb0000000000000000000000000000000000000000000000000000000081528360048201528160248201526020816044816000875af19081156101b457600091610a3b575b50156108865760207f6337ed398c0e8467698c581374fdce4db14922df487b5a39483079f5f59b60a491604051908152a3005b6020813d602011610a75575b81610a5460209383610bbe565b81010312610a715751908115158203610a6e575084610a08565b80fd5b5080fd5b3d9150610a47565b7fcf4791810000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b906020823d602011610ad7575b81610ac760209383610bbe565b81010312610a6e575051846109b3565b3d9150610aba565b346101a75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a757600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101a757817f85572ffb0000000000000000000000000000000000000000000000000000000060209314908115610b71575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610b6a565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101a757565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761074257604052565b67ffffffffffffffff811161074257601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b90600182811c92168015610c82575b6020831014610c5357565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691610c48565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101a7570180359067ffffffffffffffff82116101a7576020019181360383136101a757565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601376000858286010152011601019056fea164736f6c634300081a000a", } var MaybeRevertMessageReceiverABI = MaybeRevertMessageReceiverMetaData.ABI @@ -184,6 +184,28 @@ func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorRaw) Tran return _MaybeRevertMessageReceiver.Contract.contract.Transact(opts, method, params...) } +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCaller) BalanceOfToken(opts *bind.CallOpts, token common.Address) (*big.Int, error) { + var out []interface{} + err := _MaybeRevertMessageReceiver.contract.Call(opts, &out, "balanceOfToken", token) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) BalanceOfToken(token common.Address) (*big.Int, error) { + return _MaybeRevertMessageReceiver.Contract.BalanceOfToken(&_MaybeRevertMessageReceiver.CallOpts, token) +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCallerSession) BalanceOfToken(token common.Address) (*big.Int, error) { + return _MaybeRevertMessageReceiver.Contract.BalanceOfToken(&_MaybeRevertMessageReceiver.CallOpts, token) +} + func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCaller) SToRevert(opts *bind.CallOpts) (bool, error) { var out []interface{} err := _MaybeRevertMessageReceiver.contract.Call(opts, &out, "s_toRevert") @@ -228,16 +250,16 @@ func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCallerSession) Supp return _MaybeRevertMessageReceiver.Contract.SupportsInterface(&_MaybeRevertMessageReceiver.CallOpts, interfaceId) } -func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) CcipReceive(opts *bind.TransactOpts, arg0 ClientAny2EVMMessage) (*types.Transaction, error) { - return _MaybeRevertMessageReceiver.contract.Transact(opts, "ccipReceive", arg0) +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) CcipReceive(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.contract.Transact(opts, "ccipReceive", message) } -func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) CcipReceive(arg0 ClientAny2EVMMessage) (*types.Transaction, error) { - return _MaybeRevertMessageReceiver.Contract.CcipReceive(&_MaybeRevertMessageReceiver.TransactOpts, arg0) +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) CcipReceive(message ClientAny2EVMMessage) (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.Contract.CcipReceive(&_MaybeRevertMessageReceiver.TransactOpts, message) } -func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) CcipReceive(arg0 ClientAny2EVMMessage) (*types.Transaction, error) { - return _MaybeRevertMessageReceiver.Contract.CcipReceive(&_MaybeRevertMessageReceiver.TransactOpts, arg0) +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) CcipReceive(message ClientAny2EVMMessage) (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.Contract.CcipReceive(&_MaybeRevertMessageReceiver.TransactOpts, message) } func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) SetErr(opts *bind.TransactOpts, err []byte) (*types.Transaction, error) { @@ -264,6 +286,30 @@ func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) return _MaybeRevertMessageReceiver.Contract.SetRevert(&_MaybeRevertMessageReceiver.TransactOpts, toRevert) } +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) WithdrawFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.contract.Transact(opts, "withdrawFunds") +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) WithdrawFunds() (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.Contract.WithdrawFunds(&_MaybeRevertMessageReceiver.TransactOpts) +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) WithdrawFunds() (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.Contract.WithdrawFunds(&_MaybeRevertMessageReceiver.TransactOpts) +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) WithdrawTokens(opts *bind.TransactOpts, token common.Address, amount *big.Int) (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.contract.Transact(opts, "withdrawTokens", token, amount) +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) WithdrawTokens(token common.Address, amount *big.Int) (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.Contract.WithdrawTokens(&_MaybeRevertMessageReceiver.TransactOpts, token, amount) +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) WithdrawTokens(token common.Address, amount *big.Int) (*types.Transaction, error) { + return _MaybeRevertMessageReceiver.Contract.WithdrawTokens(&_MaybeRevertMessageReceiver.TransactOpts, token, amount) +} + func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { return _MaybeRevertMessageReceiver.contract.RawTransact(opts, nil) } @@ -337,7 +383,12 @@ func (it *MaybeRevertMessageReceiverMessageReceivedIterator) Close() error { } type MaybeRevertMessageReceiverMessageReceived struct { - Raw types.Log + MessageId [32]byte + SourceChainSelector uint64 + Sender []byte + Data []byte + DestTokenAmounts []ClientEVMTokenAmount + Raw types.Log } func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) FilterMessageReceived(opts *bind.FilterOpts) (*MaybeRevertMessageReceiverMessageReceivedIterator, error) { @@ -392,6 +443,271 @@ func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) ParseMess return event, nil } +type MaybeRevertMessageReceiverNativeFundsWithdrawnIterator struct { + Event *MaybeRevertMessageReceiverNativeFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *MaybeRevertMessageReceiverNativeFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(MaybeRevertMessageReceiverNativeFundsWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(MaybeRevertMessageReceiverNativeFundsWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *MaybeRevertMessageReceiverNativeFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *MaybeRevertMessageReceiverNativeFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type MaybeRevertMessageReceiverNativeFundsWithdrawn struct { + Owner common.Address + Amount *big.Int + Raw types.Log +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) FilterNativeFundsWithdrawn(opts *bind.FilterOpts, owner []common.Address) (*MaybeRevertMessageReceiverNativeFundsWithdrawnIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + + logs, sub, err := _MaybeRevertMessageReceiver.contract.FilterLogs(opts, "NativeFundsWithdrawn", ownerRule) + if err != nil { + return nil, err + } + return &MaybeRevertMessageReceiverNativeFundsWithdrawnIterator{contract: _MaybeRevertMessageReceiver.contract, event: "NativeFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) WatchNativeFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverNativeFundsWithdrawn, owner []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + + logs, sub, err := _MaybeRevertMessageReceiver.contract.WatchLogs(opts, "NativeFundsWithdrawn", ownerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(MaybeRevertMessageReceiverNativeFundsWithdrawn) + if err := _MaybeRevertMessageReceiver.contract.UnpackLog(event, "NativeFundsWithdrawn", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) ParseNativeFundsWithdrawn(log types.Log) (*MaybeRevertMessageReceiverNativeFundsWithdrawn, error) { + event := new(MaybeRevertMessageReceiverNativeFundsWithdrawn) + if err := _MaybeRevertMessageReceiver.contract.UnpackLog(event, "NativeFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type MaybeRevertMessageReceiverTokensWithdrawnIterator struct { + Event *MaybeRevertMessageReceiverTokensWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *MaybeRevertMessageReceiverTokensWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(MaybeRevertMessageReceiverTokensWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(MaybeRevertMessageReceiverTokensWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *MaybeRevertMessageReceiverTokensWithdrawnIterator) Error() error { + return it.fail +} + +func (it *MaybeRevertMessageReceiverTokensWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type MaybeRevertMessageReceiverTokensWithdrawn struct { + Token common.Address + Owner common.Address + Amount *big.Int + Raw types.Log +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) FilterTokensWithdrawn(opts *bind.FilterOpts, token []common.Address, owner []common.Address) (*MaybeRevertMessageReceiverTokensWithdrawnIterator, error) { + + var tokenRule []interface{} + for _, tokenItem := range token { + tokenRule = append(tokenRule, tokenItem) + } + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + + logs, sub, err := _MaybeRevertMessageReceiver.contract.FilterLogs(opts, "TokensWithdrawn", tokenRule, ownerRule) + if err != nil { + return nil, err + } + return &MaybeRevertMessageReceiverTokensWithdrawnIterator{contract: _MaybeRevertMessageReceiver.contract, event: "TokensWithdrawn", logs: logs, sub: sub}, nil +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) WatchTokensWithdrawn(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverTokensWithdrawn, token []common.Address, owner []common.Address) (event.Subscription, error) { + + var tokenRule []interface{} + for _, tokenItem := range token { + tokenRule = append(tokenRule, tokenItem) + } + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + + logs, sub, err := _MaybeRevertMessageReceiver.contract.WatchLogs(opts, "TokensWithdrawn", tokenRule, ownerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(MaybeRevertMessageReceiverTokensWithdrawn) + if err := _MaybeRevertMessageReceiver.contract.UnpackLog(event, "TokensWithdrawn", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) ParseTokensWithdrawn(log types.Log) (*MaybeRevertMessageReceiverTokensWithdrawn, error) { + event := new(MaybeRevertMessageReceiverTokensWithdrawn) + if err := _MaybeRevertMessageReceiver.contract.UnpackLog(event, "TokensWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type MaybeRevertMessageReceiverValueReceivedIterator struct { Event *MaybeRevertMessageReceiverValueReceived @@ -513,6 +829,10 @@ func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiver) ParseLog(log type switch log.Topics[0] { case _MaybeRevertMessageReceiver.abi.Events["MessageReceived"].ID: return _MaybeRevertMessageReceiver.ParseMessageReceived(log) + case _MaybeRevertMessageReceiver.abi.Events["NativeFundsWithdrawn"].ID: + return _MaybeRevertMessageReceiver.ParseNativeFundsWithdrawn(log) + case _MaybeRevertMessageReceiver.abi.Events["TokensWithdrawn"].ID: + return _MaybeRevertMessageReceiver.ParseTokensWithdrawn(log) case _MaybeRevertMessageReceiver.abi.Events["ValueReceived"].ID: return _MaybeRevertMessageReceiver.ParseValueReceived(log) @@ -522,7 +842,15 @@ func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiver) ParseLog(log type } func (MaybeRevertMessageReceiverMessageReceived) Topic() common.Hash { - return common.HexToHash("0xd82ce31e3523f6eeb2d24317b2b4133001e8472729657f663b68624c45f8f3e8") + return common.HexToHash("0x707732b700184c0ab3b799f43f03de9b3606a144cfb367f98291044e71972cdc") +} + +func (MaybeRevertMessageReceiverNativeFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xd50b71a2790ecccf5881141fe9ae079e17c66aace5d50ba383d443ecd398ffa5") +} + +func (MaybeRevertMessageReceiverTokensWithdrawn) Topic() common.Hash { + return common.HexToHash("0x6337ed398c0e8467698c581374fdce4db14922df487b5a39483079f5f59b60a4") } func (MaybeRevertMessageReceiverValueReceived) Topic() common.Hash { @@ -534,16 +862,22 @@ func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiver) Address() common. } type MaybeRevertMessageReceiverInterface interface { + BalanceOfToken(opts *bind.CallOpts, token common.Address) (*big.Int, error) + SToRevert(opts *bind.CallOpts) (bool, error) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) - CcipReceive(opts *bind.TransactOpts, arg0 ClientAny2EVMMessage) (*types.Transaction, error) + CcipReceive(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error) SetErr(opts *bind.TransactOpts, err []byte) (*types.Transaction, error) SetRevert(opts *bind.TransactOpts, toRevert bool) (*types.Transaction, error) + WithdrawFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + WithdrawTokens(opts *bind.TransactOpts, token common.Address, amount *big.Int) (*types.Transaction, error) + Receive(opts *bind.TransactOpts) (*types.Transaction, error) FilterMessageReceived(opts *bind.FilterOpts) (*MaybeRevertMessageReceiverMessageReceivedIterator, error) @@ -552,6 +886,18 @@ type MaybeRevertMessageReceiverInterface interface { ParseMessageReceived(log types.Log) (*MaybeRevertMessageReceiverMessageReceived, error) + FilterNativeFundsWithdrawn(opts *bind.FilterOpts, owner []common.Address) (*MaybeRevertMessageReceiverNativeFundsWithdrawnIterator, error) + + WatchNativeFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverNativeFundsWithdrawn, owner []common.Address) (event.Subscription, error) + + ParseNativeFundsWithdrawn(log types.Log) (*MaybeRevertMessageReceiverNativeFundsWithdrawn, error) + + FilterTokensWithdrawn(opts *bind.FilterOpts, token []common.Address, owner []common.Address) (*MaybeRevertMessageReceiverTokensWithdrawnIterator, error) + + WatchTokensWithdrawn(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverTokensWithdrawn, token []common.Address, owner []common.Address) (event.Subscription, error) + + ParseTokensWithdrawn(log types.Log) (*MaybeRevertMessageReceiverTokensWithdrawn, error) + FilterValueReceived(opts *bind.FilterOpts) (*MaybeRevertMessageReceiverValueReceivedIterator, error) WatchValueReceived(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverValueReceived) (event.Subscription, error) diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 3bcfca3d97e..75ad440e0fa 100644 --- a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -9,7 +9,7 @@ ether_sender_receiver: ../../../contracts/solc/ccip/EtherSenderReceiver/EtherSen fee_quoter: ../../../contracts/solc/ccip/FeeQuoter/FeeQuoter.sol/FeeQuoter.abi.json ../../../contracts/solc/ccip/FeeQuoter/FeeQuoter.sol/FeeQuoter.bin 3efd18088f1a27b497ec5b0936f54931e0e151033d5cb32649d497525a3964fa lock_release_token_pool: ../../../contracts/solc/ccip/LockReleaseTokenPool/LockReleaseTokenPool.sol/LockReleaseTokenPool.abi.json ../../../contracts/solc/ccip/LockReleaseTokenPool/LockReleaseTokenPool.sol/LockReleaseTokenPool.bin 2e73ee0da6f9a9a5722294289b969e4202476706e5d7cdb623e728831c79c28b log_message_data_receiver: ../../../contracts/solc/ccip/LogMessageDataReceiver/LogMessageDataReceiver.sol/LogMessageDataReceiver.abi.json ../../../contracts/solc/ccip/LogMessageDataReceiver/LogMessageDataReceiver.sol/LogMessageDataReceiver.bin 6fe60e48711884eae82dd95cabb1c66a5644336719fa1219df1ceceec11e6bce -maybe_revert_message_receiver: ../../../contracts/solc/ccip/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.sol/MaybeRevertMessageReceiver.abi.json ../../../contracts/solc/ccip/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.sol/MaybeRevertMessageReceiver.bin d1eb951af1027ca20cbee2c34df80fddbfd861e1695989aeebd29327cfe56584 +maybe_revert_message_receiver: ../../../contracts/solc/ccip/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.sol/MaybeRevertMessageReceiver.abi.json ../../../contracts/solc/ccip/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.sol/MaybeRevertMessageReceiver.bin ee264f67a2356cc4eebe839a5a88367cbcdc27a7520cca56263319e9afe97a1a message_hasher: ../../../contracts/solc/ccip/MessageHasher/MessageHasher.sol/MessageHasher.abi.json ../../../contracts/solc/ccip/MessageHasher/MessageHasher.sol/MessageHasher.bin ada9824b9e506bb9619e4e16657631cf87a3a6008f8586beff2893bfe46b0055 mock_usdc_token_messenger: ../../../contracts/solc/ccip/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.sol/MockE2EUSDCTokenMessenger.abi.json ../../../contracts/solc/ccip/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.sol/MockE2EUSDCTokenMessenger.bin ad7902d63667e582b93b2fad139aa53111f9fddcedf92b1d6d122d1ab7ec4bab mock_usdc_token_transmitter: ../../../contracts/solc/ccip/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.sol/MockE2EUSDCTransmitter.abi.json ../../../contracts/solc/ccip/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.sol/MockE2EUSDCTransmitter.bin ae0d090105bc248f4eccd337836ec1db760c506d6f5578e662305abbbc520fcd diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index 7b2e4506912..90fca00d19e 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -57,6 +57,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" + "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/rmn_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -1897,26 +1898,28 @@ func (sourceCCIP *SourceCCIPModule) CCIPMsg( func (sourceCCIP *SourceCCIPModule) SendRequest( receiver common.Address, gasLimit *big.Int, -) (common.Hash, time.Duration, *big.Int, error) { +) (common.Hash, time.Duration, *big.Int, []byte, error) { var d time.Duration destChainSelector, err := chainselectors.SelectorFromChainId(sourceCCIP.DestinationChainId) if err != nil { - return common.Hash{}, d, nil, fmt.Errorf("failed getting the chain selector: %w", err) + return common.Hash{}, d, nil, nil, fmt.Errorf("failed getting the chain selector: %w", err) } // form the message for transfer msg, err := sourceCCIP.CCIPMsg(receiver, sourceCCIP.Common.AllowOutOfOrder, gasLimit) if err != nil { - return common.Hash{}, d, nil, fmt.Errorf("failed forming the ccip msg: %w", err) + return common.Hash{}, d, nil, nil, fmt.Errorf("failed forming the ccip msg: %w", err) } + msgData := msg.Data + fee, err := sourceCCIP.Common.Router.GetFee(destChainSelector, msg) if err != nil { log.Info().Interface("Msg", msg).Msg("CCIP msg") reason, _ := blockchain.RPCErrorFromError(err) if reason != "" { - return common.Hash{}, d, nil, fmt.Errorf("failed getting the fee: %s", reason) + return common.Hash{}, d, nil, msgData, fmt.Errorf("failed getting the fee: %s", reason) } - return common.Hash{}, d, nil, fmt.Errorf("failed getting the fee: %w", err) + return common.Hash{}, d, nil, nil, fmt.Errorf("failed getting the fee: %w", err) } log.Info().Str("Fee", fee.String()).Msg("Calculated fee") @@ -1932,7 +1935,7 @@ func (sourceCCIP *SourceCCIPModule) SendRequest( if sendTx != nil { txHash = sendTx.Hash() } - return txHash, time.Since(timeNow), nil, fmt.Errorf("failed initiating the transfer ccip-send: %w", err) + return txHash, time.Since(timeNow), nil, nil, fmt.Errorf("failed initiating the transfer ccip-send: %w", err) } } else { sendTx, err = sourceCCIP.Common.Router.CCIPSendAndProcessTx(destChainSelector, msg, fee) @@ -1941,7 +1944,7 @@ func (sourceCCIP *SourceCCIPModule) SendRequest( if sendTx != nil { txHash = sendTx.Hash() } - return txHash, time.Since(timeNow), nil, fmt.Errorf("failed initiating the transfer ccip-send: %w", err) + return txHash, time.Since(timeNow), nil, nil, fmt.Errorf("failed initiating the transfer ccip-send: %w", err) } } @@ -1950,7 +1953,7 @@ func (sourceCCIP *SourceCCIPModule) SendRequest( Str("Send token transaction", sendTx.Hash().String()). Str("lane", fmt.Sprintf("%s-->%s", sourceCCIP.Common.ChainClient.GetNetworkName(), sourceCCIP.DestNetworkName)). Msg("Sending token") - return sendTx.Hash(), time.Since(timeNow), fee, nil + return sendTx.Hash(), time.Since(timeNow), fee, msgData, nil } func DefaultSourceCCIPModule( @@ -1996,6 +1999,7 @@ type DestCCIPModule struct { OffRamp *contracts.OffRamp ReportAcceptedWatcher *sync.Map ExecStateChangedWatcher *sync.Map + MessageReceivedWatcher *sync.Map ReportBlessedWatcher *sync.Map ReportBlessedBySeqNum *sync.Map NextSeqNumToCommit *atomic.Uint64 @@ -2124,6 +2128,8 @@ func (destCCIP *DestCCIPModule) RemoveAllRateLimitTokens(ctx context.Context) er return destCCIP.OffRamp.RemoveAllRateLimitTokens(ctx) } +var wasReceiverDappDeployed = false + // DeployContracts deploys all CCIP contracts specific to the destination chain func (destCCIP *DestCCIPModule) DeployContracts( sourceCCIP SourceCCIPModule, @@ -2244,6 +2250,10 @@ func (destCCIP *DestCCIPModule) DeployContracts( if err != nil { return fmt.Errorf("waiting for events on destination contract deployments %w", err) } + + log.Info().Str("Address", destCCIP.ReceiverDapp.Address()).Msg("Receiver Dapp Deployed") + + wasReceiverDappDeployed = true } else { destCCIP.ReceiverDapp, err = contractDeployer.NewReceiverDapp(destCCIP.ReceiverDapp.EthAddress) if err != nil { @@ -2706,6 +2716,77 @@ func (destCCIP *DestCCIPModule) AssertSeqNumberExecuted( } } +// AssertMessageContentMatch checks if the content of a received message matches the expected content within a specified timeout. +// It periodically polls the `MessageReceivedWatcher` for the specified message ID, compares the received content with the expected content, +// and returns an error if the content does not match or the timeout is exceeded. +func (destCCIP *DestCCIPModule) AssertMessageContentMatch( + lggr *zerolog.Logger, + messageID string, + expectedContent []byte, + timeout time.Duration, + reqStat *testreporters.RequestStat, +) error { + lggr.Info(). + Str("MsgID", fmt.Sprintf("0x%x", messageID)). + Str("Timeout", timeout.String()). + Msg("Waiting for message content to match") + timer := time.NewTimer(timeout) + defer timer.Stop() + resetTimerCount := 0 + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + // Load the message content from the watcher + value, ok := destCCIP.MessageReceivedWatcher.Load(messageID) + if !ok { + continue + } + + receivedContent, ok := value.([]uint8) + if !ok { + lggr.Warn(). + Str("MsgID", fmt.Sprintf("0x%x", messageID)). + Msg("Invalid content type in MessageReceivedWatcher") + return errors.New("invalid content type in MessageReceivedWatcher") + } + + // Compare the received content with the expected content + if string(receivedContent) == string(expectedContent) { + lggr.Info(). + Str("MessageID 0x%x", messageID). + Str("Received Content", string(receivedContent)). + Str("Expected Content", string(expectedContent)). + Msg("Message received and its content matches the sent content") + return nil + } + + lggr.Warn(). + Str("MessageID 0x%x", messageID). + Str("Received Content", string(receivedContent)). + Str("Expected Content", string(expectedContent)). + Msg("Message content mismatch") + + return fmt.Errorf("message content did not match for MessageID 0x%x", messageID) + + case <-timer.C: + // Handle timeout with potential connection issue recovery + if destCCIP.Common.IsConnectionRestoredRecently != nil && !destCCIP.Common.IsConnectionRestoredRecently.Load() { + if resetTimerCount > 2 { + return fmt.Errorf("possible RPC issue - message content did not match for MessageID 0x%x", messageID) + } + timer.Reset(timeout) + resetTimerCount++ + lggr.Info().Int("count of reset", resetTimerCount).Msg("Resetting timer to validate message content match") + continue + } + + return fmt.Errorf("timeout - message was not received for MessageID 0x%x", messageID) + } + } +} + func DefaultDestinationCCIPModule( logger *zerolog.Logger, testConf *testconfig.CCIPTestGroupConfig, @@ -2735,6 +2816,7 @@ func DefaultDestinationCCIPModule( ReportBlessedBySeqNum: &sync.Map{}, ExecStateChangedWatcher: &sync.Map{}, ReportAcceptedWatcher: &sync.Map{}, + MessageReceivedWatcher: &sync.Map{}, }, nil } @@ -2743,6 +2825,7 @@ type CCIPRequest struct { txHash string txConfirmationTimestamp time.Time RequestStat *testreporters.RequestStat + MessageData []byte } func CCIPRequestFromTxHash(txHash common.Hash, chainClient blockchain.EVMClient) (CCIPRequest, *types.Receipt, error) { @@ -2895,7 +2978,7 @@ func (lane *CCIPLane) RecordStateBeforeTransfer() { lane.SentReqs = make(map[common.Hash][]CCIPRequest) } -func (lane *CCIPLane) AddToSentReqs(txHash common.Hash, reqStats []*testreporters.RequestStat) (*types.Receipt, error) { +func (lane *CCIPLane) AddToSentReqs(txHash common.Hash, reqStats []*testreporters.RequestStat, msgData []byte) (*types.Receipt, error) { request, rcpt, err := CCIPRequestFromTxHash(txHash, lane.Source.Common.ChainClient) if err != nil { for _, stat := range reqStats { @@ -2910,6 +2993,7 @@ func (lane *CCIPLane) AddToSentReqs(txHash common.Hash, reqStats []*testreporter txHash: rcpt.TxHash.Hex(), txConfirmationTimestamp: request.txConfirmationTimestamp, RequestStat: stat, + MessageData: msgData, }) lane.NumberOfReq++ } @@ -2996,7 +3080,7 @@ func (lane *CCIPLane) Multicall(noOfRequests int, multiSendAddr common.Address) } return fmt.Errorf("failed to send the multicall: %w", err) } - rcpt, err := lane.AddToSentReqs(tx.Hash(), reqStats) + rcpt, err := lane.AddToSentReqs(tx.Hash(), reqStats, nil) if err != nil { return err } @@ -3018,7 +3102,7 @@ func (lane *CCIPLane) Multicall(noOfRequests int, multiSendAddr common.Address) func (lane *CCIPLane) SendRequests(noOfRequests int, gasLimit *big.Int) error { for i := 1; i <= noOfRequests; i++ { stat := testreporters.NewCCIPRequestStats(int64(lane.NumberOfReq+i), lane.SourceNetworkName, lane.DestNetworkName) - txHash, txConfirmationDur, fee, err := lane.Source.SendRequest(lane.Dest.ReceiverDapp.EthAddress, gasLimit) + txHash, txConfirmationDur, fee, msgData, err := lane.Source.SendRequest(lane.Dest.ReceiverDapp.EthAddress, gasLimit) if err != nil { stat.UpdateState(lane.Logger, 0, testreporters.TX, txConfirmationDur, testreporters.Failure, nil) return fmt.Errorf("could not send request: %w", err) @@ -3035,7 +3119,7 @@ func (lane *CCIPLane) SendRequests(noOfRequests int, gasLimit *big.Int) error { noOfTokens++ } } - _, err = lane.AddToSentReqs(txHash, []*testreporters.RequestStat{stat}) + _, err = lane.AddToSentReqs(txHash, []*testreporters.RequestStat{stat}, msgData) if err != nil { return err } @@ -3345,7 +3429,17 @@ func (lane *CCIPLane) ValidateRequestByTxHash(txHash common.Hash, opts validatio if shouldReturn, phaseErr := isPhaseValid(lane.Logger, testreporters.ExecStateChanged, opts, err); shouldReturn { return phaseErr } + + if wasReceiverDappDeployed && lane.SentReqs[txHash][0].MessageData != nil { + err = lane.Dest.AssertMessageContentMatch(lane.Logger, string(msgLog.MessageId[:]), lane.SentReqs[txHash][0].MessageData, timeout, reqStat) + if err != nil { + return errors.Wrap(err, "message validation failed") + } + + log.Info().Msg("Message content validation successful") + } } + if opts.expectAnyPhaseToFail { return errors.New("expected at least any one phase to fail but no phase got failed") } @@ -3550,6 +3644,35 @@ func (lane *CCIPLane) StartEventWatchers() error { } }(reportAccSub) + messageReceivedEvent := make(chan *maybe_revert_message_receiver.MaybeRevertMessageReceiverMessageReceived) + messageReceivedSub := event.Resubscribe(DefaultResubscriptionTimeout, func(_ context.Context) (event.Subscription, error) { + sub, err := lane.Dest.ReceiverDapp.WatchMessageReceived(nil, messageReceivedEvent) + if err != nil { + log.Error().Err(err).Msg("error in subscribing to message received event") + } + return sub, err + }) + if messageReceivedSub == nil { + return errors.New("failed to subscribe to message received event") + } + go func(sub event.Subscription) { + defer sub.Unsubscribe() + for { + select { + case e := <-messageReceivedEvent: + messageID := string(e.MessageId[:]) + messageContent := e.Data + messageSender := string(e.Sender) + log.Info().Msgf("Message event received for message id: 0x%x", messageID) + log.Info().Msgf("Message event received with content: %+v", string(messageContent)) + log.Info().Msgf("Message event received with sender: 0x%x", messageSender[len(messageSender)-20:]) + lane.Dest.MessageReceivedWatcher.Store(messageID, messageContent) + case <-lane.Context.Done(): + return + } + } + }(messageReceivedSub) + if lane.Dest.Common.ARM != nil { reportBlessedEvent := make(chan *rmn_contract.RMNContractTaggedRootBlessed) blessedSub := event.Resubscribe(DefaultResubscriptionTimeout, func(_ context.Context) (event.Subscription, error) { diff --git a/integration-tests/ccip-tests/contracts/contract_models.go b/integration-tests/ccip-tests/contracts/contract_models.go index 01245daa966..9ed310c3379 100644 --- a/integration-tests/ccip-tests/contracts/contract_models.go +++ b/integration-tests/ccip-tests/contracts/contract_models.go @@ -1104,6 +1104,19 @@ func (rDapp *ReceiverDapp) ToggleRevert(revert bool) error { return rDapp.client.ProcessTransaction(tx) } +// WatchMessageReceived watches for `MessageReceived` events from the ReceiverDapp contract. +func (rDapp *ReceiverDapp) WatchMessageReceived(opts *bind.WatchOpts, messageReceivedEvent chan *maybe_revert_message_receiver.MaybeRevertMessageReceiverMessageReceived) (event.Subscription, error) { + if rDapp.instance != nil { + return rDapp.instance.WatchMessageReceived(opts, messageReceivedEvent) + } + + newInstance, err := maybe_revert_message_receiver.NewMaybeRevertMessageReceiver(rDapp.EthAddress, wrappers.MustNewWrappedContractBackend(rDapp.client, nil)) + if err != nil { + return nil, fmt.Errorf("failed to create a new ReceiverDapp contract instance: %w", err) + } + return newInstance.WatchMessageReceived(opts, messageReceivedEvent) +} + type InternalTimestampedPackedUint224 struct { Value *big.Int Timestamp uint32 diff --git a/integration-tests/ccip-tests/load/helper.go b/integration-tests/ccip-tests/load/helper.go index f89aadc2483..47e379809af 100644 --- a/integration-tests/ccip-tests/load/helper.go +++ b/integration-tests/ccip-tests/load/helper.go @@ -206,7 +206,7 @@ func (l *LoadArgs) ValidateCurseFollowedByUncurse() { // try to send requests on lanes on which curse is applied on source RMN and the request should revert // data-only transfer is sufficient lane.Source.TransferAmount = []*big.Int{} - failedTx, _, _, err := lane.Source.SendRequest(lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err := lane.Source.SendRequest(lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) if lane.Source.Common.ChainClient.GetNetworkConfig().MinimumConfirmations > 0 { require.Error(l.t, err) } else { diff --git a/integration-tests/ccip-tests/smoke/ccip_test.go b/integration-tests/ccip-tests/smoke/ccip_test.go index 344b920f852..e52fd993c34 100644 --- a/integration-tests/ccip-tests/smoke/ccip_test.go +++ b/integration-tests/ccip-tests/smoke/ccip_test.go @@ -250,7 +250,7 @@ func TestSmokeCCIPRateLimit(t *testing.T) { tc.lane.Source.Common.ChainClient.GetDefaultWallet(), src.Common.Router.Address(), src.TransferAmount[0]), ) require.NoError(t, tc.lane.Source.Common.ChainClient.WaitForEvents()) - failedTx, _, _, err := tc.lane.Source.SendRequest( + failedTx, _, _, _, err := tc.lane.Source.SendRequest( tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit), ) @@ -278,7 +278,7 @@ func TestSmokeCCIPRateLimit(t *testing.T) { // try to send again with amount more than the amount refilled by rate and // this should fail, as the refill rate is not enough to refill the capacity src.TransferAmount[0] = new(big.Int).Mul(AggregatedRateLimitRate, big.NewInt(10)) - failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) tc.lane.Logger.Info().Str("tokensToSend", src.TransferAmount[0].String()).Msg("More than Aggregated Rate") require.NoError(t, err) require.Error(t, tc.lane.Source.Common.ChainClient.WaitForEvents()) @@ -342,7 +342,7 @@ func TestSmokeCCIPRateLimit(t *testing.T) { src.TransferAmount[0] = tokensToSend tc.lane.Logger.Info().Str("tokensToSend", tokensToSend.String()).Msg("More than Token Pool Capacity") - failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) require.NoError(t, err) require.Error(t, tc.lane.Source.Common.ChainClient.WaitForEvents()) errReason, v, err = tc.lane.Source.Common.ChainClient.RevertReasonFromTx(failedTx, lock_release_token_pool.LockReleaseTokenPoolABI) @@ -374,7 +374,7 @@ func TestSmokeCCIPRateLimit(t *testing.T) { src.Common.ChainClient.GetDefaultWallet(), src.Common.Router.Address(), src.TransferAmount[0]), ) require.NoError(t, tc.lane.Source.Common.ChainClient.WaitForEvents()) - failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) require.NoError(t, err) require.Error(t, tc.lane.Source.Common.ChainClient.WaitForEvents()) errReason, v, err = tc.lane.Source.Common.ChainClient.RevertReasonFromTx(failedTx, lock_release_token_pool.LockReleaseTokenPoolABI) @@ -508,7 +508,7 @@ func TestSmokeCCIPOnRampLimits(t *testing.T) { src.TransferAmount[bpsTokenIndex] = big.NewInt(0) src.TransferAmount[aggRateTokenIndex] = overCapacityAmount src.TransferAmount[bpsAndAggTokenIndex] = big.NewInt(0) - failedTx, _, _, err := tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err := tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) require.Error(t, err, "Limited token transfer should immediately revert") errReason, _, err := src.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI) require.NoError(t, err) @@ -520,7 +520,7 @@ func TestSmokeCCIPOnRampLimits(t *testing.T) { src.TransferAmount[aggRateTokenIndex] = big.NewInt(0) src.TransferAmount[bpsAndAggTokenIndex] = overCapacityAmount - failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) require.Error(t, err, "Limited token transfer should immediately revert") errReason, _, err = src.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI) require.NoError(t, err) @@ -568,7 +568,7 @@ func TestSmokeCCIPOnRampLimits(t *testing.T) { src.TransferAmount[bpsTokenIndex] = big.NewInt(0) src.TransferAmount[aggRateTokenIndex] = capacityLimit src.TransferAmount[bpsAndAggTokenIndex] = big.NewInt(0) - failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) require.Error(t, err, "Aggregate rate limited token transfer should immediately revert") errReason, _, err = src.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI) require.NoError(t, err) @@ -580,7 +580,7 @@ func TestSmokeCCIPOnRampLimits(t *testing.T) { src.TransferAmount[aggRateTokenIndex] = big.NewInt(0) src.TransferAmount[bpsAndAggTokenIndex] = capacityLimit - failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) require.Error(t, err, "Aggregate rate limited token transfer should immediately revert") errReason, _, err = src.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI) require.NoError(t, err) @@ -701,7 +701,7 @@ func TestSmokeCCIPTokenPoolRateLimits(t *testing.T) { // Send limited token over capacity and ensure it fails src.TransferAmount[freeTokenIndex] = big.NewInt(0) src.TransferAmount[limitedTokenIndex] = overCapacityAmount - failedTx, _, _, err := tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err := tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) require.Error(t, err, "Limited token transfer should immediately revert") errReason, _, err := src.Common.ChainClient.RevertReasonFromTx(failedTx, lock_release_token_pool.LockReleaseTokenPoolABI) require.NoError(t, err) @@ -732,7 +732,7 @@ func TestSmokeCCIPTokenPoolRateLimits(t *testing.T) { // Send limited token over rate limit and ensure it fails src.TransferAmount[freeTokenIndex] = big.NewInt(0) src.TransferAmount[limitedTokenIndex] = capacityLimit - failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) + failedTx, _, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit)) require.Error(t, err, "Limited token transfer should immediately revert") errReason, _, err = src.Common.ChainClient.RevertReasonFromTx(failedTx, lock_release_token_pool.LockReleaseTokenPoolABI) require.NoError(t, err) From 6118cc68949a8ebd14a2ae06ab18aea08463a19f Mon Sep 17 00:00:00 2001 From: Yashvardhan Nevatia Date: Fri, 31 Jan 2025 15:31:24 +0530 Subject: [PATCH 22/43] Changesets for solana tokenPool, billing, registry (#16088) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding solchains in NewEnv * Revert "Adding solchains in NewEnv" This reverts commit aaab52e01412ea4f1de4f748cadf0c127682418c. * adding sol chains to newenv * newEnv needs to send nil * adding test env setup * adding link token deployment and test * adding nil for crib sol chains * using switch case * Adding decimal const * adding chain selectors commit * go mod tidy * adding initial code for solana chain contracts deploy * linting * adding solana state * adding initial code for solana chain contracts deploy * wip * chain sel update * update core/scripts go files * again * add changeset * go imports * go mod * go mod * go mod tidy * todo * deploy stuff * Adding solana router deploy * Adding * updates * adding stuff for tests * linting * linting * changing to ctf * bug * Add CI Action to build Solana contracts * testing stuff * continue testing * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Update action.yml * deployment: memory: Generate more transmitter key types, expose in JD * deployment: memory: Configure nodes with solana config too * Use CTF to spin up the solana validator for in-memory tests * Use autopatchelf on solana binaries to make them usable on NixOS * memory: solana: Shut down the container when test terminates * go mod tidy * Use latest upstream CTF * Add missing import * make modgraph * Use framework.DefaultNetwork() * changes * tidying * ignoring keypair if not provided * fix * adding solchains to newnodes * adding home chain changes * delegate changes * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Update action.yml * test integrating with CI build step * working tests * bump ccip * test fix * save existing solana + tests * try reading program ids * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Update chain.go * Update action.yml * last try * Update action.yml * Update action.yml * make script executable * reverting changes to stabilize the branch * Create ccip_router.so * go mod tidy * sol chains param * linting * adding build here * try without parallel * yash fixed it! * function signature * Update chain.go * parallel * try defer * retries * still linting * Revert "retries" This reverts commit f9f5fd2823210d873f79d6b8c351dbed8a3221b4. * revert * lint * gomod * remove cleanup * fix deps * try empty map * Revert "yash fixed it!" This reverts commit ff35f2113fe94b86001dd8af6266a0936059680f. * remove token info changes * revert function call * revert * go mod tidy * no return * try retries * try returning again * use CI artifact * try without ctf bump * CR comments * lint * add global lookup table * call utils * adding token pool deploy * test commit * adding solana token stufF * adding token pool so * add retries * fix token test * setup token pool last * match lookup table from tests * lint * revert token pool uncomment * skip early return * remove retries * add ccip receiver to helpers * initial token admin registry * billing * adding billing stuff * cr comments * fix home chain * test fix * run receiver in CI * skip receiver again * change set program id * addLane for solana * clean up supported chain checks * using AddLane for evm to sol * make it one operation * adding router account check for router init (solana) * adding default commitment to solana_chain * Adding support for solana in validateRemoteChain * Adding test TestUpdateOnRampsDestsSolana * move to switch * Revmoing solana from UpdateOnRampsDests * adding separate solana AddRemoteChainToSolana * moving to changeset_solana * Reuse GetAccountDataBorshInto * validation comment * update test helpers based on AddRemoteChainOnSolana * AddRemoteChainOnSolana test update * uncommenting test but this will break * validation comment * remove token pools; consolidate home chain * Revert "test commit" This reverts commit 2f315cdaa6fc267afaf95580124d9818ea7af284. * lint * cleanup * cleanup * cr comments * cr comments * reverting UpdateOnRampDestsConfig * bumping chainlink-ccip * use common PDA functions * tokenSymbol * solana tooling dev * adding back token pool deploy and converting token state to list * Adding token stuff * Revert "cleanup" This reverts commit 7388c49a3d45a702143e4ffcaf35c751ed325c4a. * delete artifacts again * adding logic for add token pool * Adding wsol * adding SetupTokenPoolForRemoteChain * adding changesets * move solana logic * lint * lint * gomodtidy * move parallel calls * cr comments * lint * adding token pool setup and billing * merging * gitignore solana contracts * lint * lint * token admin registry tests * addressing comments * fix remote config check * Revert "solana tooling dev" This reverts commit 866a1d547c7773af59cf68fd2a2ad8d77e5fee68. * linting * lint * linting * error wrapping --------- Co-authored-by: Terry Tata Co-authored-by: jlaveracll Co-authored-by: Blaž Hrastnik Co-authored-by: tt-cll <141346969+tt-cll@users.noreply.github.com> --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- deployment/ccip/changeset/cs_deploy_chain.go | 82 +- .../changeset/solana/cs_chain_contracts.go | 802 ++++++++++++++++-- .../solana/cs_chain_contracts_test.go | 285 ++++++- .../changeset/solana/cs_deploy_chain_test.go | 3 +- .../ccip/changeset/solana/cs_solana_token.go | 134 +-- .../changeset/solana/cs_solana_token_test.go | 54 +- deployment/ccip/changeset/solana_state.go | 114 +-- .../changeset/testhelpers/test_helpers.go | 65 +- .../common/changeset/deploy_link_token.go | 21 +- deployment/environment/memory/chain.go | 2 +- deployment/go.mod | 2 +- deployment/go.sum | 4 +- deployment/solana_chain.go | 67 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 +- 19 files changed, 1297 insertions(+), 356 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 56abdb380c0..9918da212a5 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -316,7 +316,7 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect github.com/smartcontractkit/chain-selectors v1.0.37 // indirect github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 // indirect - github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect + github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index ed18faef765..fa92de23163 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1331,8 +1331,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= -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-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= +github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= diff --git a/deployment/ccip/changeset/cs_deploy_chain.go b/deployment/ccip/changeset/cs_deploy_chain.go index a2c761feb1c..2042493ea1d 100644 --- a/deployment/ccip/changeset/cs_deploy_chain.go +++ b/deployment/ccip/changeset/cs_deploy_chain.go @@ -17,6 +17,7 @@ import ( chainsel "github.com/smartcontractkit/chain-selectors" solRouter "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router" solCommonUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" + solState "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/state" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" @@ -558,37 +559,42 @@ func solRouterProgramData(e deployment.Environment, chain deployment.SolChain, c return programData, nil } -func initializeRouter(e deployment.Environment, chain deployment.SolChain, ccipRouterProgram solana.PublicKey) error { +func initializeRouter(e deployment.Environment, chain deployment.SolChain, ccipRouterProgram solana.PublicKey, linkTokenAddress solana.PublicKey) error { programData, err := solRouterProgramData(e, chain, ccipRouterProgram) if err != nil { return fmt.Errorf("failed to get solana router program data: %w", err) } + // addressing errcheck in the next PR + routerConfigPDA, _, _ := solState.FindConfigPDA(ccipRouterProgram) + routerStatePDA, _, _ := solState.FindStatePDA(ccipRouterProgram) + externalExecutionConfigPDA, _, _ := solState.FindExternalExecutionConfigPDA(ccipRouterProgram) + externalTokenPoolsSignerPDA, _, _ := solState.FindExternalTokenPoolsSignerPDA(ccipRouterProgram) instruction, err := solRouter.NewInitializeInstruction( - chain.Selector, // chain selector - deployment.SolDefaultGasLimit, // default gas limit - true, // allow out of order execution - EnableExecutionAfter, // period to wait before allowing manual execution - solana.PublicKey{}, // fee aggregator - GetRouterConfigPDA(ccipRouterProgram), - GetRouterStatePDA(ccipRouterProgram), + chain.Selector, // chain selector + deployment.SolDefaultGasLimit, // default gas limit + true, // allow out of order execution + EnableExecutionAfter, // period to wait before allowing manual execution + solana.PublicKey{}, // fee aggregator (TODO: changeset to set the fee aggregator) + linkTokenAddress, // link token mint + deployment.SolDefaultMaxFeeJuelsPerMsg, // max fee juels per msg + routerConfigPDA, + routerStatePDA, chain.DeployerKey.PublicKey(), solana.SystemProgramID, ccipRouterProgram, programData.Address, - GetExternalExecutionConfigPDA(ccipRouterProgram), - GetExternalTokenPoolsSignerPDA(ccipRouterProgram), + externalExecutionConfigPDA, + externalTokenPoolsSignerPDA, ).ValidateAndBuild() if err != nil { return fmt.Errorf("failed to build instruction: %w", err) } - - err = chain.Confirm([]solana.Instruction{instruction}) - if err != nil { + if err := chain.Confirm([]solana.Instruction{instruction}); err != nil { return fmt.Errorf("failed to confirm instructions: %w", err) } - + e.Logger.Infow("Initialized router", "chain", chain.String()) return nil } @@ -604,10 +610,11 @@ func deployChainContractsSolana( } chainState, chainExists := state.SolChains[chain.Selector] if !chainExists { - return fmt.Errorf("chain %s not found in existing state, deploy the prerequisites first", chain.String()) + return fmt.Errorf("chain %s not found in existing state, deploy the link token first", chain.String()) + } + if chainState.LinkToken.IsZero() { + return fmt.Errorf("failed to get link token address for chain %s", chain.String()) } - linkTokenContract := chainState.LinkToken - e.Logger.Infow("link token", "addr", linkTokenContract.String()) // ROUTER DEPLOY AND INITIALIZE var ccipRouterProgram solana.PublicKey @@ -634,17 +641,44 @@ func deployChainContractsSolana( // check if solana router is initialised var routerConfigAccount solRouter.Config - err = chain.GetAccountDataBorshInto(e.GetContext(), GetRouterConfigPDA(ccipRouterProgram), &routerConfigAccount) + // addressing errcheck in the next PR + routerConfigPDA, _, _ := solState.FindConfigPDA(ccipRouterProgram) + err = chain.GetAccountDataBorshInto(e.GetContext(), routerConfigPDA, &routerConfigAccount) if err != nil { - if err2 := initializeRouter(e, chain, ccipRouterProgram); err2 != nil { + if err2 := initializeRouter(e, chain, ccipRouterProgram, chainState.LinkToken); err2 != nil { return err2 } } else { e.Logger.Infow("Router already initialized, skipping initialization", "chain", chain.String()) } + var tokenPoolProgram solana.PublicKey + if chainState.TokenPool.IsZero() { + // TODO: there should be two token pools deployed one of each type (lock/burn) + // separate token pools are not ready yet + programID, err := chain.DeployProgram(e.Logger, "token_pool") + if err != nil { + return fmt.Errorf("failed to deploy program: %w", err) + } + tv := deployment.NewTypeAndVersion(TokenPool, deployment.Version1_0_0) + e.Logger.Infow("Deployed contract", "Contract", tv.String(), "addr", programID, "chain", chain.String()) + tokenPoolProgram = solana.MustPublicKeyFromBase58(programID) + err = ab.Save(chain.Selector, programID, tv) + if err != nil { + return fmt.Errorf("failed to save address: %w", err) + } + } else { + e.Logger.Infow("Using existing token pool", "addr", chainState.TokenPool.String()) + tokenPoolProgram = chainState.TokenPool + } + // initialize this last with every address we need if chainState.AddressLookupTable.IsZero() { + // addressing errcheck in the next PR + routerConfigPDA, _, _ := solState.FindConfigPDA(ccipRouterProgram) + routerStatePDA, _, _ := solState.FindStatePDA(ccipRouterProgram) + externalExecutionConfigPDA, _, _ := solState.FindExternalExecutionConfigPDA(ccipRouterProgram) + externalTokenPoolsSignerPDA, _, _ := solState.FindExternalTokenPoolsSignerPDA(ccipRouterProgram) table, err := solCommonUtil.SetupLookupTable( e.GetContext(), chain.Client, @@ -656,10 +690,12 @@ func deployChainContractsSolana( solana.SysVarInstructionsPubkey, // router ccipRouterProgram, - GetRouterConfigPDA(ccipRouterProgram), - GetRouterStatePDA(ccipRouterProgram), - GetExternalExecutionConfigPDA(ccipRouterProgram), - GetExternalTokenPoolsSignerPDA(ccipRouterProgram), + routerConfigPDA, + routerStatePDA, + externalExecutionConfigPDA, + externalTokenPoolsSignerPDA, + // token pools + tokenPoolProgram, // token solana.Token2022ProgramID, solana.TokenProgramID, diff --git a/deployment/ccip/changeset/solana/cs_chain_contracts.go b/deployment/ccip/changeset/solana/cs_chain_contracts.go index 6447ba92ba1..b87cc284421 100644 --- a/deployment/ccip/changeset/solana/cs_chain_contracts.go +++ b/deployment/ccip/changeset/solana/cs_chain_contracts.go @@ -1,21 +1,110 @@ package solana import ( + "context" + "errors" "fmt" "github.com/gagliardetto/solana-go" - "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router" solRouter "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router" + "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/token_pool" solCommonUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" + solState "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/state" + solTokenUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/tokens" + + ata "github.com/gagliardetto/solana-go/programs/associated-token-account" + + chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" cs "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" ) +var _ deployment.ChangeSet[AddRemoteChainToSolanaConfig] = AddRemoteChainToSolana +var _ deployment.ChangeSet[TokenPoolConfig] = AddTokenPool +var _ deployment.ChangeSet[RemoteChainTokenPoolConfig] = SetupTokenPoolForRemoteChain +var _ deployment.ChangeSet[cs.SetOCR3OffRampConfig] = SetOCR3ConfigSolana +var _ deployment.ChangeSet[BillingTokenConfig] = AddBillingToken +var _ deployment.ChangeSet[BillingTokenForRemoteChainConfig] = AddBillingTokenForRemoteChain +var _ deployment.ChangeSet[RegisterTokenAdminRegistryConfig] = RegisterTokenAdminRegistry +var _ deployment.ChangeSet[TransferAdminRoleTokenAdminRegistryConfig] = TransferAdminRoleTokenAdminRegistry +var _ deployment.ChangeSet[AcceptAdminRoleTokenAdminRegistryConfig] = AcceptAdminRoleTokenAdminRegistry + +// GetTokenProgramID returns the program ID for the given token program name +func GetTokenProgramID(programName string) (solana.PublicKey, error) { + tokenPrograms := map[string]solana.PublicKey{ + deployment.SPLTokens: solana.TokenProgramID, // not used yet + deployment.SPL2022Tokens: solana.Token2022ProgramID, + } + + programID, ok := tokenPrograms[programName] + if !ok { + return solana.PublicKey{}, fmt.Errorf("invalid token program: %s. Must be one of: %s, %s", programName, deployment.SPLTokens, deployment.SPL2022Tokens) + } + return programID, nil +} + +// GetPoolType returns the token pool type constant for the given string +func GetPoolType(poolType string) (token_pool.PoolType, error) { + poolTypes := map[string]token_pool.PoolType{ + "LockAndRelease": token_pool.LockAndRelease_PoolType, + "BurnAndMint": token_pool.BurnAndMint_PoolType, + } + + poolTypeConstant, ok := poolTypes[poolType] + if !ok { + return 0, fmt.Errorf("invalid pool type: %s. Must be one of: LockAndRelease, BurnAndMint", poolType) + } + return poolTypeConstant, nil +} + +func commonValidation(e deployment.Environment, selector uint64, tokenPubKey solana.PublicKey) error { + chain, ok := e.SolChains[selector] + if !ok { + return fmt.Errorf("chain selector %d not found in environment", selector) + } + state, err := cs.LoadOnchainState(e) + if err != nil { + return fmt.Errorf("failed to load onchain state: %w", err) + } + chainState, chainExists := state.SolChains[selector] + if !chainExists { + return fmt.Errorf("chain %s not found in existing state, deploy the link token first", chain.String()) + } + if tokenPubKey.Equals(chainState.LinkToken) || tokenPubKey.Equals(chainState.WSOL) { + return nil + } + exists := false + for _, token := range chainState.SPL2022Tokens { + if token.Equals(tokenPubKey) { + exists = true + break + } + } + if !exists { + return fmt.Errorf("token %s not found in existing state, deploy the token first", tokenPubKey.String()) + } + return nil +} + +func validateRouterConfig(chain deployment.SolChain, chainState cs.SolCCIPChainState) error { + if chainState.Router.IsZero() { + return fmt.Errorf("router not found in existing state, deploy the router first chain %d", chain.Selector) + } + // addressing errcheck in the next PR + routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) + var routerConfigAccount solRouter.Config + err := chain.GetAccountDataBorshInto(context.Background(), routerConfigPDA, &routerConfigAccount) + if err != nil { + return fmt.Errorf("router config not found in existing state, initialize the router first %d", chain.Selector) + } + return nil +} + +// ADD REMOTE CHAIN type AddRemoteChainToSolanaConfig struct { // UpdatesByChain is a mapping of SVM chain selector -> remote chain selector -> remote chain config update UpdatesByChain map[uint64]map[uint64]RemoteChainConfigSolana @@ -26,22 +115,22 @@ type AddRemoteChainToSolanaConfig struct { // https://github.com/smartcontractkit/chainlink-ccip/blob/771fb9957d818253d833431e7e980669984e1d6a/chains/solana/gobindings/ccip_router/types.go#L1141 // https://github.com/smartcontractkit/chainlink-ccip/blob/771fb9957d818253d833431e7e980669984e1d6a/chains/solana/contracts/tests/ccip/ccip_router_test.go#L130 +// We are not using solRouter.SourceChainConfig because that would involve the user +// converting the onRamp address into [2][64]byte{} which is not intuitive. +// The solRouter.DestChainConfig on the other hand has a lot of fields and most of them are uint +// So we are using that directly instead of copying over the fields here to reduce +// overhead cost if that type is bumped in chainlink-ccip type RemoteChainConfigSolana struct { - EnabledAsSource bool - EnabledAsDestination bool - // TODO: what if remote chain family is solana ? will this be the router address ? - RemoteChainOnRampAddress string - DefaultTxGasLimit uint32 - MaxPerMsgGasLimit uint32 - MaxDataBytes uint32 - MaxNumberOfTokensPerMsg uint16 - ChainFamilySelector [4]uint8 + // source + EnabledAsSource bool + // destination + DestinationConfig solRouter.DestChainConfig } func (cfg AddRemoteChainToSolanaConfig) Validate(e deployment.Environment) error { state, err := cs.LoadOnchainState(e) if err != nil { - return err + return fmt.Errorf("failed to load onchain state: %w", err) } supportedChains := state.SupportedChains() @@ -50,27 +139,24 @@ func (cfg AddRemoteChainToSolanaConfig) Validate(e deployment.Environment) error if !ok { return fmt.Errorf("chain %d not found in onchain state", chainSel) } - - if chainState.Router.IsZero() { - return fmt.Errorf("missing router for chain %d", chainSel) + chain := e.SolChains[chainSel] + if err := validateRouterConfig(chain, chainState); err != nil { + return err } - if err := commoncs.ValidateOwnershipSolana(e.GetContext(), cfg.MCMS != nil, e.SolChains[chainSel].DeployerKey.PublicKey(), chainState.Timelock, chainState.Router); err != nil { - return err + return fmt.Errorf("failed to validate ownership: %w", err) } - + routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) var routerConfigAccount solRouter.Config - err = solCommonUtil.GetAccountDataBorshInto(e.GetContext(), e.SolChains[chainSel].Client, cs.GetRouterConfigPDA(chainState.Router), deployment.SolDefaultCommitment, &routerConfigAccount) - if err != nil { - return fmt.Errorf("failed to get router config %s: %w", chainState.Router, err) - } + // already validated that router config exists + _ = chain.GetAccountDataBorshInto(context.Background(), routerConfigPDA, &routerConfigAccount) for remote := range updates { if _, ok := supportedChains[remote]; !ok { return fmt.Errorf("remote chain %d is not supported", remote) } - if remote == routerConfigAccount.SolanaChainSelector { - return fmt.Errorf("cannot add remote chain with same chain selector as current chain %d", remote) + if remote == routerConfigAccount.SvmChainSelector { + return fmt.Errorf("cannot add remote chain %d with same chain selector as current chain %d", remote, chainSel) } } } @@ -100,38 +186,41 @@ func AddRemoteChainToSolana(e deployment.Environment, cfg AddRemoteChainToSolana } func doAddRemoteChainToSolana(e deployment.Environment, s cs.CCIPOnChainState, chainSel uint64, updates map[uint64]RemoteChainConfigSolana) (deployment.ChangesetOutput, error) { - e.Logger.Infow("Adding remote chain to solana", "chain", chainSel, "updates", updates) chain := e.SolChains[chainSel] - ccipRouterID := s.SolChains[chainSel].Router - // TODO: will this fail if chain has already been added? - for destination, update := range updates { - // TODO: this should be GetSourceChainStatePDA - sourceChainStatePDA := cs.GetEvmSourceChainStatePDA(ccipRouterID, destination) + for remoteChainSel, update := range updates { + var onRampBytes [64]byte + // already verified, skipping errcheck + remoteChainFamily, _ := chainsel.GetSelectorFamily(remoteChainSel) + switch remoteChainFamily { + case chainsel.FamilySolana: + return deployment.ChangesetOutput{}, fmt.Errorf("support for solana chain as remote chain is not implemented yet %d", remoteChainSel) + case chainsel.FamilyEVM: + onRampAddress := s.Chains[remoteChainSel].OnRamp.Address().String() + if onRampAddress == "" { + return deployment.ChangesetOutput{}, fmt.Errorf("onramp address not found for chain %d", remoteChainSel) + } + addressBytes := []byte(onRampAddress) + copy(onRampBytes[:], addressBytes) + } + validSourceChainConfig := solRouter.SourceChainConfig{ - OnRamp: []byte(update.RemoteChainOnRampAddress), + OnRamp: [2][64]byte{onRampBytes, [64]byte{}}, IsEnabled: update.EnabledAsSource, } - // TODO: this should be GetDestChainStatePDA - destChainStatePDA := cs.GetEvmDestChainStatePDA(ccipRouterID, destination) - validDestChainConfig := solRouter.DestChainConfig{ - IsEnabled: update.EnabledAsDestination, - DefaultTxGasLimit: update.DefaultTxGasLimit, - MaxPerMsgGasLimit: update.MaxPerMsgGasLimit, - MaxDataBytes: update.MaxDataBytes, - MaxNumberOfTokensPerMsg: update.MaxNumberOfTokensPerMsg, - // TODO: what if chain family is solana ? - // bytes4(keccak256("CCIP ChainFamilySelector EVM")) - ChainFamilySelector: [4]uint8{40, 18, 213, 44}, - } + // addressing errcheck in the next PR + routerConfigPDA, _, _ := solState.FindConfigPDA(ccipRouterID) + destChainStatePDA, _ := solState.FindDestChainStatePDA(remoteChainSel, ccipRouterID) + sourceChainStatePDA, _ := solState.FindSourceChainStatePDA(remoteChainSel, ccipRouterID) + instruction, err := solRouter.NewAddChainSelectorInstruction( - destination, + remoteChainSel, validSourceChainConfig, - validDestChainConfig, + update.DestinationConfig, sourceChainStatePDA, destChainStatePDA, - cs.GetRouterConfigPDA(ccipRouterID), + routerConfigPDA, chain.DeployerKey.PublicKey(), solana.SystemProgramID, ).ValidateAndBuild() @@ -151,6 +240,7 @@ func doAddRemoteChainToSolana(e deployment.Environment, s cs.CCIPOnChainState, c return deployment.ChangesetOutput{}, nil } +// SET OCR3 CONFIG func btoi(b bool) uint8 { if b { return 1 @@ -171,7 +261,7 @@ func SetOCR3ConfigSolana(e deployment.Environment, cfg cs.SetOCR3OffRampConfig) state, err := cs.LoadOnchainState(e) if err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } solChains := state.SolChains @@ -183,39 +273,42 @@ func SetOCR3ConfigSolana(e deployment.Environment, cfg cs.SetOCR3OffRampConfig) state.Chains[cfg.HomeChainSel].CCIPHome, remote) if err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get don id for chain %d: %w", remote, err) } args, err := internal.BuildSetOCR3ConfigArgsSolana(donID, state.Chains[cfg.HomeChainSel].CCIPHome, remote) if err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, fmt.Errorf("failed to build set ocr3 config args: %w", err) } // TODO: check if ocr3 has already been set // set, err := isOCR3ConfigSetSolana(e.Logger, e.Chains[remote], state.Chains[remote].OffRamp, args) var instructions []solana.Instruction ccipRouterID := solChains[remote].Router + // addressing errcheck in the next PR + routerConfigPDA, _, _ := solState.FindConfigPDA(ccipRouterID) + routerStatePDA, _, _ := solState.FindStatePDA(ccipRouterID) for _, arg := range args { - instruction, err := ccip_router.NewSetOcrConfigInstruction( + instruction, err := solRouter.NewSetOcrConfigInstruction( arg.OCRPluginType, - ccip_router.Ocr3ConfigInfo{ + solRouter.Ocr3ConfigInfo{ ConfigDigest: arg.ConfigDigest, F: arg.F, IsSignatureVerificationEnabled: btoi(arg.IsSignatureVerificationEnabled), }, arg.Signers, arg.Transmitters, - changeset.GetRouterConfigPDA(ccipRouterID), - changeset.GetRouterStatePDA(ccipRouterID), + routerConfigPDA, + routerStatePDA, e.SolChains[remote].DeployerKey.PublicKey(), ).ValidateAndBuild() if err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) } instructions = append(instructions, instruction) } if cfg.MCMS == nil { err := e.SolChains[remote].Confirm(instructions) if err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) } } } @@ -224,3 +317,602 @@ func SetOCR3ConfigSolana(e deployment.Environment, cfg cs.SetOCR3OffRampConfig) // TODO: timelock mcms support } + +// ADD TOKEN POOL +type TokenPoolConfig struct { + ChainSelector uint64 + PoolType string + Authority string + TokenPubKey string + TokenProgramName string +} + +func (cfg TokenPoolConfig) Validate(e deployment.Environment) error { + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil { + return err + } + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + if chainState.TokenPool.IsZero() { + return fmt.Errorf("token pool not found in existing state, deploy the token pool first for chain %d", cfg.ChainSelector) + } + if _, err := GetPoolType(cfg.PoolType); err != nil { + return err + } + if _, err := GetTokenProgramID(cfg.TokenProgramName); err != nil { + return err + } + + tokenPool := chainState.TokenPool + poolConfigPDA, err := solTokenUtil.TokenPoolConfigAddress(tokenPubKey, tokenPool) + if err != nil { + return fmt.Errorf("failed to get token pool config address (mint: %s, pool: %s): %w", tokenPubKey.String(), tokenPool.String(), err) + } + chain := e.SolChains[cfg.ChainSelector] + var poolConfigAccount token_pool.Config + if err := chain.GetAccountDataBorshInto(context.Background(), poolConfigPDA, &poolConfigAccount); err == nil { + return fmt.Errorf("token pool config already exists for (mint: %s, pool: %s)", tokenPubKey.String(), tokenPool.String()) + } + return nil +} + +func AddTokenPool(e deployment.Environment, cfg TokenPoolConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + chain := e.SolChains[cfg.ChainSelector] + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + authorityPubKey := solana.MustPublicKeyFromBase58(cfg.Authority) + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + + // verified + tokenprogramID, _ := GetTokenProgramID(cfg.TokenProgramName) + poolType, _ := GetPoolType(cfg.PoolType) + poolConfigPDA, _ := solTokenUtil.TokenPoolConfigAddress(tokenPubKey, chainState.TokenPool) + poolSigner, _ := solTokenUtil.TokenPoolSignerAddress(tokenPubKey, chainState.TokenPool) + + // addressing errcheck in the next PR + rampAuthorityPubKey, _, _ := solState.FindExternalExecutionConfigPDA(chainState.Router) + + // ata for token pool + createI, tokenPoolATA, err := solTokenUtil.CreateAssociatedTokenAccount( + tokenprogramID, + tokenPubKey, + poolSigner, + chain.DeployerKey.PublicKey(), + ) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create associated token account for tokenpool (mint: %s, pool: %s): %w", tokenPubKey.String(), chainState.TokenPool.String(), err) + } + + token_pool.SetProgramID(chainState.TokenPool) + // initialize token pool for token + poolInitI, err := token_pool.NewInitializeInstruction( + poolType, + rampAuthorityPubKey, + poolConfigPDA, + tokenPubKey, + poolSigner, + authorityPubKey, // this is assumed to be chain.DeployerKey for now (owner of token pool) + solana.SystemProgramID, + ).ValidateAndBuild() + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + // make pool mint_authority for token (required for burn/mint) + authI, err := solTokenUtil.SetTokenMintAuthority( + tokenprogramID, + poolSigner, + tokenPubKey, + chain.DeployerKey.PublicKey(), + ) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + instructions := []solana.Instruction{createI, poolInitI, authI} + + // add signer here if authority is different from deployer key + if err := chain.Confirm(instructions); err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) + } + e.Logger.Infow("Created new token pool config", "token_pool_ata", tokenPoolATA.String(), "pool_config", poolConfigPDA.String(), "pool_signer", poolSigner.String()) + e.Logger.Infow("Set mint authority", "poolSigner", poolSigner.String()) + + return deployment.ChangesetOutput{}, nil +} + +// ADD TOKEN POOL FOR REMOTE CHAIN +type RemoteChainTokenPoolConfig struct { + ChainSelector uint64 + RemoteChainSelector uint64 + TokenPubKey string + RemoteConfig token_pool.RemoteConfig + InboundRateLimit token_pool.RateLimitConfig + OutboundRateLimit token_pool.RateLimitConfig +} + +func (cfg RemoteChainTokenPoolConfig) Validate(e deployment.Environment) error { + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + if err := commonValidation(e, cfg.ChainSelector, solana.MustPublicKeyFromBase58(cfg.TokenPubKey)); err != nil { + return err + } + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + if chainState.TokenPool.IsZero() { + return fmt.Errorf("token pool not found in existing state, deploy token pool for chain %d", cfg.ChainSelector) + } + + chain := e.SolChains[cfg.ChainSelector] + tokenPool := chainState.TokenPool + + // check if pool config exists (cannot do remote setup without it) + poolConfigPDA, err := solTokenUtil.TokenPoolConfigAddress(tokenPubKey, tokenPool) + if err != nil { + return fmt.Errorf("failed to get token pool config address (mint: %s, pool: %s): %w", tokenPubKey.String(), tokenPool.String(), err) + } + var poolConfigAccount token_pool.Config + if err := chain.GetAccountDataBorshInto(context.Background(), poolConfigPDA, &poolConfigAccount); err != nil { + return fmt.Errorf("token pool config not found (mint: %s, pool: %s): %w", tokenPubKey.String(), chainState.TokenPool.String(), err) + } + + // check if existing pool setup already has this remote chain configured + remoteChainConfigPDA, _, err := solTokenUtil.TokenPoolChainConfigPDA(cfg.RemoteChainSelector, tokenPubKey, tokenPool) + if err != nil { + return fmt.Errorf("failed to get token pool remote chain config pda (remoteSelector: %d, mint: %s, pool: %s): %w", cfg.RemoteChainSelector, tokenPubKey.String(), tokenPool.String(), err) + } + var remoteChainConfigAccount token_pool.ChainConfig + if err := chain.GetAccountDataBorshInto(context.Background(), remoteChainConfigPDA, &remoteChainConfigAccount); err == nil { + return fmt.Errorf("remote chain config already exists for (remoteSelector: %d, mint: %s, pool: %s)", cfg.RemoteChainSelector, tokenPubKey.String(), tokenPool.String()) + } + return nil +} + +func SetupTokenPoolForRemoteChain(e deployment.Environment, cfg RemoteChainTokenPoolConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + chain := e.SolChains[cfg.ChainSelector] + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + // verified + poolConfigPDA, _ := solTokenUtil.TokenPoolConfigAddress(tokenPubKey, chainState.TokenPool) + remoteChainConfigPDA, _, _ := solTokenUtil.TokenPoolChainConfigPDA(cfg.RemoteChainSelector, tokenPubKey, chainState.TokenPool) + + token_pool.SetProgramID(chainState.TokenPool) + ixConfigure, err := token_pool.NewInitChainRemoteConfigInstruction( + cfg.RemoteChainSelector, + tokenPubKey, + cfg.RemoteConfig, + poolConfigPDA, + remoteChainConfigPDA, + chain.DeployerKey.PublicKey(), + solana.SystemProgramID, + ).ValidateAndBuild() + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + ixRates, err := token_pool.NewSetChainRateLimitInstruction( + cfg.RemoteChainSelector, + tokenPubKey, + cfg.InboundRateLimit, + cfg.OutboundRateLimit, + poolConfigPDA, + remoteChainConfigPDA, + chain.DeployerKey.PublicKey(), + solana.SystemProgramID, + ).ValidateAndBuild() + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + instructions := []solana.Instruction{ixConfigure, ixRates} + err = chain.Confirm(instructions) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) + } + return deployment.ChangesetOutput{}, nil +} + +// ADD BILLING TOKEN +type BillingTokenConfig struct { + ChainSelector uint64 + TokenPubKey string + TokenProgramName string + Config solRouter.BillingTokenConfig +} + +func (cfg BillingTokenConfig) Validate(e deployment.Environment) error { + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil { + return err + } + if _, err := GetTokenProgramID(cfg.TokenProgramName); err != nil { + return err + } + + chain := e.SolChains[cfg.ChainSelector] + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + if err := validateRouterConfig(chain, chainState); err != nil { + return err + } + // check if already setup + billingConfigPDA, _, err := solState.FindFeeBillingTokenConfigPDA(tokenPubKey, chainState.Router) + if err != nil { + return fmt.Errorf("failed to find billing token config pda (mint: %s, router: %s): %w", tokenPubKey.String(), chainState.Router.String(), err) + } + var token0ConfigAccount solRouter.BillingTokenConfigWrapper + if err := chain.GetAccountDataBorshInto(context.Background(), billingConfigPDA, &token0ConfigAccount); err == nil { + return fmt.Errorf("billing token config already exists for (mint: %s, router: %s)", tokenPubKey.String(), chainState.Router.String()) + } + return nil +} + +func AddBillingToken(e deployment.Environment, cfg BillingTokenConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + chain, ok := e.SolChains[cfg.ChainSelector] + if !ok { + return deployment.ChangesetOutput{}, fmt.Errorf("chain selector %d not found in environment", cfg.ChainSelector) + } + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + + solRouter.SetProgramID(chainState.Router) + + // verified + tokenprogramID, _ := GetTokenProgramID(cfg.TokenProgramName) + routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) + billingConfigPDA, _, _ := solState.FindFeeBillingTokenConfigPDA(tokenPubKey, chainState.Router) + + // addressing errcheck in the next PR + billingSignerPDA, _, _ := solState.FindFeeBillingSignerPDA(chainState.Router) + token2022Receiver, _, _ := solTokenUtil.FindAssociatedTokenAddress(tokenprogramID, tokenPubKey, billingSignerPDA) + + ixConfig, cerr := solRouter.NewAddBillingTokenConfigInstruction( + cfg.Config, + routerConfigPDA, + billingConfigPDA, + tokenprogramID, + tokenPubKey, + token2022Receiver, + chain.DeployerKey.PublicKey(), // ccip admin + billingSignerPDA, + ata.ProgramID, + solana.SystemProgramID, + ).ValidateAndBuild() + if cerr != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", cerr) + } + + instructions := []solana.Instruction{ixConfig} + if err := chain.Confirm(instructions); err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) + } + e.Logger.Infow("Billing token added", "chainSelector", cfg.ChainSelector, "tokenPubKey", tokenPubKey.String()) + return deployment.ChangesetOutput{}, nil +} + +// ADD BILLING TOKEN FOR REMOTE CHAIN +type BillingTokenForRemoteChainConfig struct { + ChainSelector uint64 + RemoteChainSelector uint64 + Config solRouter.TokenBilling + TokenPubKey string +} + +func (cfg BillingTokenForRemoteChainConfig) Validate(e deployment.Environment) error { + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil { + return err + } + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + chain := e.SolChains[cfg.ChainSelector] + if err := validateRouterConfig(chain, chainState); err != nil { + return fmt.Errorf("router validation failed: %w", err) + } + // check if desired state already exists + remoteBillingPDA, _, err := solState.FindCcipTokenpoolBillingPDA(cfg.RemoteChainSelector, tokenPubKey, chainState.Router) + if err != nil { + return fmt.Errorf("failed to find remote billing token config pda for (remoteSelector: %d, mint: %s, router: %s): %w", cfg.RemoteChainSelector, tokenPubKey.String(), chainState.Router.String(), err) + } + var remoteBillingAccount solRouter.TokenBilling + if err := chain.GetAccountDataBorshInto(context.Background(), remoteBillingPDA, &remoteBillingAccount); err == nil { + return fmt.Errorf("billing token config already exists for (remoteSelector: %d, mint: %s, router: %s)", cfg.RemoteChainSelector, tokenPubKey.String(), chainState.Router.String()) + } + return nil +} + +func AddBillingTokenForRemoteChain(e deployment.Environment, cfg BillingTokenForRemoteChainConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + + chain := e.SolChains[cfg.ChainSelector] + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + // verified + remoteBillingPDA, _, _ := solState.FindCcipTokenpoolBillingPDA(cfg.RemoteChainSelector, tokenPubKey, chainState.Router) + routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) + + ix, err := solRouter.NewSetTokenBillingInstruction( + cfg.RemoteChainSelector, + tokenPubKey, + cfg.Config, + routerConfigPDA, + remoteBillingPDA, + chain.DeployerKey.PublicKey(), + solana.SystemProgramID, + ).ValidateAndBuild() + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + instructions := []solana.Instruction{ix} + if err := chain.Confirm(instructions); err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) + } + e.Logger.Infow("Token billing set for remote chain", "chainSelector ", cfg.ChainSelector, "remoteChainSelector ", cfg.RemoteChainSelector, "tokenPubKey", tokenPubKey.String()) + return deployment.ChangesetOutput{}, nil +} + +// TOKEN ADMIN REGISTRY +type RegisterTokenAdminRegistryType int + +const ( + ViaGetCcipAdminInstruction RegisterTokenAdminRegistryType = iota + ViaOwnerInstruction +) + +type RegisterTokenAdminRegistryConfig struct { + ChainSelector uint64 + TokenPubKey string + TokenAdminRegistryAdmin string + RegisterType RegisterTokenAdminRegistryType +} + +func (cfg RegisterTokenAdminRegistryConfig) Validate(e deployment.Environment) error { + if cfg.RegisterType != ViaGetCcipAdminInstruction && cfg.RegisterType != ViaOwnerInstruction { + return fmt.Errorf("invalid register type, valid types are %d and %d", ViaGetCcipAdminInstruction, ViaOwnerInstruction) + } + + if cfg.RegisterType == ViaOwnerInstruction && cfg.TokenAdminRegistryAdmin != "" { + return errors.New("token admin registry should be empty for via owner instruction") + } + + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil { + return err + } + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + chain := e.SolChains[cfg.ChainSelector] + if err := validateRouterConfig(chain, chainState); err != nil { + return err + } + tokenAdminRegistryPDA, _, err := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) + if err != nil { + return fmt.Errorf("failed to find token admin registry pda (mint: %s, router: %s): %w", tokenPubKey.String(), chainState.Router.String(), err) + } + var tokenAdminRegistryAccount solRouter.TokenAdminRegistry + if err := chain.GetAccountDataBorshInto(context.Background(), tokenAdminRegistryPDA, &tokenAdminRegistryAccount); err == nil { + return fmt.Errorf("token admin registry already exists for (mint: %s, router: %s)", tokenPubKey.String(), chainState.Router.String()) + } + return nil +} + +func RegisterTokenAdminRegistry(e deployment.Environment, cfg RegisterTokenAdminRegistryConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + chain := e.SolChains[cfg.ChainSelector] + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + + // verified + routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) + tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) + + var instruction *solRouter.Instruction + var err error + switch cfg.RegisterType { + // the ccip admin signs and makes tokenAdminRegistryAdmin the authority of the tokenAdminRegistry PDA + case ViaGetCcipAdminInstruction: + tokenAdminRegistryAdmin := solana.MustPublicKeyFromBase58(cfg.TokenAdminRegistryAdmin) + instruction, err = solRouter.NewRegisterTokenAdminRegistryViaGetCcipAdminInstruction( + tokenPubKey, + tokenAdminRegistryAdmin, // admin of the tokenAdminRegistry PDA + routerConfigPDA, + tokenAdminRegistryPDA, // this gets created + chain.DeployerKey.PublicKey(), // (ccip admin) + solana.SystemProgramID, + ).ValidateAndBuild() + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + case ViaOwnerInstruction: + // the token mint authority signs and makes itself the authority of the tokenAdminRegistry PDA + instruction, err = solRouter.NewRegisterTokenAdminRegistryViaOwnerInstruction( + routerConfigPDA, + tokenAdminRegistryPDA, // this gets created + tokenPubKey, + chain.DeployerKey.PublicKey(), // (token mint authority) becomes the authority of the tokenAdminRegistry PDA + solana.SystemProgramID, + ).ValidateAndBuild() + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + } + // if we want to have a different authority, we will need to add the corresponding singer here + // for now we are assuming both token owner and ccip admin will always be deployer key + instructions := []solana.Instruction{instruction} + if err := chain.Confirm(instructions); err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) + } + return deployment.ChangesetOutput{}, nil +} + +// TRANSFER AND ACCEPT TOKEN ADMIN REGISTRY +type TransferAdminRoleTokenAdminRegistryConfig struct { + ChainSelector uint64 + TokenPubKey string + NewRegistryAdminPublicKey string + CurrentRegistryAdminPrivateKey string +} + +func (cfg TransferAdminRoleTokenAdminRegistryConfig) Validate(e deployment.Environment) error { + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil { + return err + } + + currentRegistryAdminPrivateKey := solana.MustPrivateKeyFromBase58(cfg.CurrentRegistryAdminPrivateKey) + newRegistryAdminPubKey := solana.MustPublicKeyFromBase58(cfg.NewRegistryAdminPublicKey) + + if currentRegistryAdminPrivateKey.PublicKey().Equals(newRegistryAdminPubKey) { + return fmt.Errorf("new registry admin public key (%s) cannot be the same as current registry admin public key (%s) for token %s", + newRegistryAdminPubKey.String(), + currentRegistryAdminPrivateKey.PublicKey().String(), + tokenPubKey.String(), + ) + } + + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + chain := e.SolChains[cfg.ChainSelector] + if err := validateRouterConfig(chain, chainState); err != nil { + return err + } + tokenAdminRegistryPDA, _, err := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) + if err != nil { + return fmt.Errorf("failed to find token admin registry pda (mint: %s, router: %s): %w", tokenPubKey.String(), chainState.Router.String(), err) + } + var tokenAdminRegistryAccount solRouter.TokenAdminRegistry + if err := chain.GetAccountDataBorshInto(context.Background(), tokenAdminRegistryPDA, &tokenAdminRegistryAccount); err != nil { + return fmt.Errorf("token admin registry not found for (mint: %s, router: %s), cannot transfer admin role", tokenPubKey.String(), chainState.Router.String()) + } + // check if passed admin is the current admin + if !tokenAdminRegistryAccount.Administrator.Equals(currentRegistryAdminPrivateKey.PublicKey()) { + return fmt.Errorf("current registry admin private key (%s) does not match administrator (%s) for token %s", + currentRegistryAdminPrivateKey.PublicKey().String(), + tokenAdminRegistryAccount.Administrator.String(), + tokenPubKey.String(), + ) + } + return nil +} + +func TransferAdminRoleTokenAdminRegistry(e deployment.Environment, cfg TransferAdminRoleTokenAdminRegistryConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + chain := e.SolChains[cfg.ChainSelector] + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + + // verified + tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) + routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) + + currentRegistryAdminPrivateKey := solana.MustPrivateKeyFromBase58(cfg.CurrentRegistryAdminPrivateKey) + newRegistryAdminPubKey := solana.MustPublicKeyFromBase58(cfg.NewRegistryAdminPublicKey) + + ix1, err := solRouter.NewTransferAdminRoleTokenAdminRegistryInstruction( + tokenPubKey, + newRegistryAdminPubKey, + routerConfigPDA, + tokenAdminRegistryPDA, + currentRegistryAdminPrivateKey.PublicKey(), // as we are assuming this is the default authority for everything in the beginning + ).ValidateAndBuild() + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + instructions := []solana.Instruction{ix1} + // the existing authority will have to sign the transfer + if err := chain.Confirm(instructions, solCommonUtil.AddSigners(currentRegistryAdminPrivateKey)); err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) + } + return deployment.ChangesetOutput{}, nil +} + +type AcceptAdminRoleTokenAdminRegistryConfig struct { + ChainSelector uint64 + TokenPubKey string + NewRegistryAdminPrivateKey string +} + +func (cfg AcceptAdminRoleTokenAdminRegistryConfig) Validate(e deployment.Environment) error { + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil { + return err + } + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + chain := e.SolChains[cfg.ChainSelector] + if err := validateRouterConfig(chain, chainState); err != nil { + return err + } + tokenAdminRegistryPDA, _, err := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) + if err != nil { + return fmt.Errorf("failed to find token admin registry pda (mint: %s, router: %s): %w", tokenPubKey.String(), chainState.Router.String(), err) + } + var tokenAdminRegistryAccount solRouter.TokenAdminRegistry + if err := chain.GetAccountDataBorshInto(context.Background(), tokenAdminRegistryPDA, &tokenAdminRegistryAccount); err != nil { + return fmt.Errorf("token admin registry not found for (mint: %s, router: %s), cannot accept admin role", tokenPubKey.String(), chainState.Router.String()) + } + // check if accepting admin is the pending admin + newRegistryAdminPrivateKey := solana.MustPrivateKeyFromBase58(cfg.NewRegistryAdminPrivateKey) + newRegistryAdminPublicKey := newRegistryAdminPrivateKey.PublicKey() + if !tokenAdminRegistryAccount.PendingAdministrator.Equals(newRegistryAdminPublicKey) { + return fmt.Errorf("new admin public key (%s) does not match pending registry admin role (%s) for token %s", + newRegistryAdminPublicKey.String(), + tokenAdminRegistryAccount.PendingAdministrator.String(), + tokenPubKey.String(), + ) + } + return nil +} + +func AcceptAdminRoleTokenAdminRegistry(e deployment.Environment, cfg AcceptAdminRoleTokenAdminRegistryConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + chain := e.SolChains[cfg.ChainSelector] + state, _ := cs.LoadOnchainState(e) + chainState := state.SolChains[cfg.ChainSelector] + tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) + newRegistryAdminPrivateKey := solana.MustPrivateKeyFromBase58(cfg.NewRegistryAdminPrivateKey) + + // verified + tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) + routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) + + ix1, err := solRouter.NewAcceptAdminRoleTokenAdminRegistryInstruction( + tokenPubKey, + routerConfigPDA, + tokenAdminRegistryPDA, + newRegistryAdminPrivateKey.PublicKey(), + ).ValidateAndBuild() + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + } + + instructions := []solana.Instruction{ix1} + // the new authority will have to sign the acceptance + if err := chain.Confirm(instructions, solCommonUtil.AddSigners(newRegistryAdminPrivateKey)); err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) + } + return deployment.ChangesetOutput{}, nil +} + +// TODO (all look up table related changesets): +// Update look up tables with tokens and pools +// Set Pool (https://smartcontract-it.atlassian.net/browse/INTAUTO-437) +// NewAppendRemotePoolAddressesInstruction (https://smartcontract-it.atlassian.net/browse/INTAUTO-436) diff --git a/deployment/ccip/changeset/solana/cs_chain_contracts_test.go b/deployment/ccip/changeset/solana/cs_chain_contracts_test.go index 80965a42a91..a7b489a5aa4 100644 --- a/deployment/ccip/changeset/solana/cs_chain_contracts_test.go +++ b/deployment/ccip/changeset/solana/cs_chain_contracts_test.go @@ -1,13 +1,22 @@ package solana_test import ( + "context" + "math/big" "testing" + "github.com/gagliardetto/solana-go" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/deployment" + solRouter "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router" + "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/token_pool" + solState "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/state" + solTokenUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/tokens" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + ccipChangeset "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" changeset_solana "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/solana" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" @@ -48,13 +57,19 @@ func TestAddRemoteChain(t *testing.T) { UpdatesByChain: map[uint64]map[uint64]changeset_solana.RemoteChainConfigSolana{ solChain: { evmChain: { - EnabledAsSource: true, - EnabledAsDestination: true, - RemoteChainOnRampAddress: state.Chains[evmChain].OnRamp.Address().String(), - DefaultTxGasLimit: 1, - MaxPerMsgGasLimit: 100, - MaxDataBytes: 32, - MaxNumberOfTokensPerMsg: 1, + EnabledAsSource: true, + DestinationConfig: solRouter.DestChainConfig{ + IsEnabled: true, + DefaultTxGasLimit: 200000, + MaxPerMsgGasLimit: 3000000, + MaxDataBytes: 30000, + MaxNumberOfTokensPerMsg: 5, + DefaultTokenDestGasOverhead: 5000, + // bytes4(keccak256("CCIP ChainFamilySelector EVM")) + // TODO: do a similar test for other chain families + // https://smartcontract-it.atlassian.net/browse/INTAUTO-438 + ChainFamilySelector: [4]uint8{40, 18, 213, 44}, + }, }, }, }, @@ -67,14 +82,14 @@ func TestAddRemoteChain(t *testing.T) { require.NoError(t, err) var sourceChainStateAccount solRouter.SourceChain - evmSourceChainStatePDA := changeset.GetEvmSourceChainStatePDA(state.SolChains[solChain].Router, evmChain) + evmSourceChainStatePDA, _ := solState.FindSourceChainStatePDA(evmChain, state.SolChains[solChain].Router) err = tenv.Env.SolChains[solChain].GetAccountDataBorshInto(ctx, evmSourceChainStatePDA, &sourceChainStateAccount) require.NoError(t, err) require.Equal(t, uint64(1), sourceChainStateAccount.State.MinSeqNr) require.True(t, sourceChainStateAccount.Config.IsEnabled) var destChainStateAccount solRouter.DestChain - evmDestChainStatePDA := changeset.GetEvmDestChainStatePDA(state.SolChains[solChain].Router, evmChain) + evmDestChainStatePDA, _ := solState.FindDestChainStatePDA(evmChain, state.SolChains[solChain].Router) err = tenv.Env.SolChains[solChain].GetAccountDataBorshInto(ctx, evmDestChainStatePDA, &destChainStateAccount) require.NoError(t, err) } @@ -83,3 +98,255 @@ func TestDeployCCIPContracts(t *testing.T) { t.Parallel() testhelpers.DeployCCIPContractsTest(t, 1) } + +func TestAddTokenPool(t *testing.T) { + t.Parallel() + + tenv, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithSolChains(1)) + + evmChain := tenv.Env.AllChainSelectors()[0] + solChain := tenv.Env.AllChainSelectorsSolana()[0] + + e, err := commonchangeset.ApplyChangesets(t, tenv.Env, nil, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset_solana.DeploySolanaToken), + Config: changeset_solana.DeploySolanaTokenConfig{ + ChainSelector: solChain, + TokenProgramName: deployment.SPL2022Tokens, + TokenDecimals: 9, + }, + }, + }) + require.NoError(t, err) + + state, err := ccipChangeset.LoadOnchainStateSolana(e) + require.NoError(t, err) + tokenAddress := state.SolChains[solChain].SPL2022Tokens[0] + + // TODO: can test this with solana.SolMint as well (WSOL) + // https://smartcontract-it.atlassian.net/browse/INTAUTO-440 + e, err = commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset_solana.AddTokenPool), + Config: changeset_solana.TokenPoolConfig{ + ChainSelector: solChain, + TokenPubKey: tokenAddress.String(), + TokenProgramName: deployment.SPL2022Tokens, + PoolType: "LockAndRelease", + // this works for testing, but if we really want some other authority we need to pass in a private key for signing purposes + Authority: e.SolChains[solChain].DeployerKey.PublicKey().String(), + }, + }, + { + Changeset: commonchangeset.WrapChangeSet(changeset_solana.SetupTokenPoolForRemoteChain), + Config: changeset_solana.RemoteChainTokenPoolConfig{ + ChainSelector: solChain, + RemoteChainSelector: evmChain, + TokenPubKey: tokenAddress.String(), + RemoteConfig: token_pool.RemoteConfig{ + PoolAddresses: []token_pool.RemoteAddress{{Address: []byte{1, 2, 3}}}, + TokenAddress: token_pool.RemoteAddress{Address: []byte{4, 5, 6}}, + Decimals: 9, + }, + InboundRateLimit: token_pool.RateLimitConfig{ + Enabled: true, + Capacity: uint64(1000), + Rate: 1, + }, + OutboundRateLimit: token_pool.RateLimitConfig{ + Enabled: false, + Capacity: 0, + Rate: 0, + }, + }, + }, + }) + require.NoError(t, err) + + // test AddTokenPool results + poolConfigPDA, err := solTokenUtil.TokenPoolConfigAddress(tokenAddress, state.SolChains[solChain].TokenPool) + require.NoError(t, err) + var configAccount token_pool.Config + err = e.SolChains[solChain].GetAccountDataBorshInto(context.Background(), poolConfigPDA, &configAccount) + t.Logf("configAccount: %+v", configAccount) + require.NoError(t, err) + require.Equal(t, token_pool.LockAndRelease_PoolType, configAccount.PoolType) + require.Equal(t, tokenAddress, configAccount.Mint) + // try minting after this and see if the pool or the deployer key is the authority + + // test SetupTokenPoolForRemoteChain results + remoteChainConfigPDA, _, _ := solTokenUtil.TokenPoolChainConfigPDA(evmChain, tokenAddress, state.SolChains[solChain].TokenPool) + var remoteChainConfigAccount token_pool.ChainConfig + err = e.SolChains[solChain].GetAccountDataBorshInto(context.Background(), remoteChainConfigPDA, &remoteChainConfigAccount) + require.NoError(t, err) + require.Equal(t, uint8(9), remoteChainConfigAccount.Remote.Decimals) +} + +func TestBilling(t *testing.T) { + t.Parallel() + + tenv, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithSolChains(1)) + + evmChain := tenv.Env.AllChainSelectors()[0] + solChain := tenv.Env.AllChainSelectorsSolana()[0] + + e, err := commonchangeset.ApplyChangesets(t, tenv.Env, nil, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset_solana.DeploySolanaToken), + Config: changeset_solana.DeploySolanaTokenConfig{ + ChainSelector: solChain, + TokenProgramName: deployment.SPL2022Tokens, + TokenDecimals: 9, + }, + }, + }) + require.NoError(t, err) + + state, err := ccipChangeset.LoadOnchainStateSolana(e) + require.NoError(t, err) + tokenAddress := state.SolChains[solChain].SPL2022Tokens[0] + validTimestamp := int64(100) + value := [28]uint8{} + bigNum, ok := new(big.Int).SetString("19816680000000000000", 10) + require.True(t, ok) + bigNum.FillBytes(value[:]) + e, err = commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset_solana.AddBillingToken), + Config: changeset_solana.BillingTokenConfig{ + ChainSelector: solChain, + TokenPubKey: tokenAddress.String(), + TokenProgramName: deployment.SPL2022Tokens, + Config: solRouter.BillingTokenConfig{ + Enabled: true, + Mint: tokenAddress, + UsdPerToken: solRouter.TimestampedPackedU224{ + Timestamp: validTimestamp, + Value: value, + }, + PremiumMultiplierWeiPerEth: 100, + }, + }, + }, + { + Changeset: commonchangeset.WrapChangeSet(changeset_solana.AddBillingTokenForRemoteChain), + Config: changeset_solana.BillingTokenForRemoteChainConfig{ + ChainSelector: solChain, + RemoteChainSelector: evmChain, + TokenPubKey: tokenAddress.String(), + Config: solRouter.TokenBilling{ + MinFeeUsdcents: 800, + MaxFeeUsdcents: 1600, + DeciBps: 0, + DestGasOverhead: 100, + DestBytesOverhead: 100, + IsEnabled: true, + }, + }, + }, + }) + require.NoError(t, err) + + billingConfigPDA, _, _ := solState.FindFeeBillingTokenConfigPDA(tokenAddress, state.SolChains[solChain].Router) + var token0ConfigAccount solRouter.BillingTokenConfigWrapper + err = e.SolChains[solChain].GetAccountDataBorshInto(context.Background(), billingConfigPDA, &token0ConfigAccount) + require.NoError(t, err) + require.True(t, token0ConfigAccount.Config.Enabled) + require.Equal(t, tokenAddress, token0ConfigAccount.Config.Mint) + + remoteBillingPDA, _, _ := solState.FindCcipTokenpoolBillingPDA(evmChain, tokenAddress, state.SolChains[solChain].Router) + var remoteBillingAccount solRouter.PerChainPerTokenConfig + err = e.SolChains[solChain].GetAccountDataBorshInto(context.Background(), remoteBillingPDA, &remoteBillingAccount) + require.NoError(t, err) + require.Equal(t, tokenAddress, remoteBillingAccount.Mint) + require.Equal(t, uint32(800), remoteBillingAccount.Billing.MinFeeUsdcents) +} + +func TestTokenAdminRegistry(t *testing.T) { + t.Parallel() + + tenv, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithSolChains(1)) + + solChain := tenv.Env.AllChainSelectorsSolana()[0] + + e, err := commonchangeset.ApplyChangesets(t, tenv.Env, nil, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset_solana.DeploySolanaToken), + Config: changeset_solana.DeploySolanaTokenConfig{ + ChainSelector: solChain, + TokenProgramName: deployment.SPL2022Tokens, + TokenDecimals: 9, + }, + }, + }) + require.NoError(t, err) + + state, err := ccipChangeset.LoadOnchainStateSolana(e) + require.NoError(t, err) + tokenAddress := state.SolChains[solChain].SPL2022Tokens[0] + tokenAdminRegistryAdminPrivKey, _ := solana.NewRandomPrivateKey() + + // We have to do run the ViaOwnerInstruction testcase for linkToken as we already registered a PDA for tokenAddress in the previous testcase + linkTokenAddress := state.SolChains[solChain].LinkToken + + e, err = commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{ + { // register token admin registry for tokenAddress via getCcipAdminInstruction + Changeset: commonchangeset.WrapChangeSet(changeset_solana.RegisterTokenAdminRegistry), + Config: changeset_solana.RegisterTokenAdminRegistryConfig{ + ChainSelector: solChain, + TokenPubKey: tokenAddress.String(), + TokenAdminRegistryAdmin: tokenAdminRegistryAdminPrivKey.PublicKey().String(), + RegisterType: changeset_solana.ViaGetCcipAdminInstruction, + }, + }, + { // register token admin registry for linkToken via owner instruction + Changeset: commonchangeset.WrapChangeSet(changeset_solana.RegisterTokenAdminRegistry), + Config: changeset_solana.RegisterTokenAdminRegistryConfig{ + ChainSelector: solChain, + TokenPubKey: linkTokenAddress.String(), + RegisterType: changeset_solana.ViaOwnerInstruction, + }, + }, + { // transfer admin role for tokenAddress + Changeset: commonchangeset.WrapChangeSet(changeset_solana.TransferAdminRoleTokenAdminRegistry), + Config: changeset_solana.TransferAdminRoleTokenAdminRegistryConfig{ + ChainSelector: solChain, + TokenPubKey: tokenAddress.String(), + CurrentRegistryAdminPrivateKey: tokenAdminRegistryAdminPrivKey.String(), + NewRegistryAdminPublicKey: e.SolChains[solChain].DeployerKey.PublicKey().String(), + }, + }, + }) + require.NoError(t, err) + + tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenAddress, state.SolChains[solChain].Router) + var tokenAdminRegistryAccount solRouter.TokenAdminRegistry + err = e.SolChains[solChain].GetAccountDataBorshInto(context.Background(), tokenAdminRegistryPDA, &tokenAdminRegistryAccount) + require.NoError(t, err) + require.Equal(t, tokenAdminRegistryAdminPrivKey.PublicKey(), tokenAdminRegistryAccount.Administrator) + // pending administrator should be the deployer key + require.Equal(t, e.SolChains[solChain].DeployerKey.PublicKey(), tokenAdminRegistryAccount.PendingAdministrator) + + linkTokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(linkTokenAddress, state.SolChains[solChain].Router) + var linkTokenAdminRegistryAccount solRouter.TokenAdminRegistry + err = e.SolChains[solChain].GetAccountDataBorshInto(context.Background(), linkTokenAdminRegistryPDA, &linkTokenAdminRegistryAccount) + require.NoError(t, err) + // as DeployLinkToken (DeploySolanaToken) makes the deployer key the authority of the token, it should be the administrator of the tokenAdminRegistry via owner instruction + require.Equal(t, e.SolChains[solChain].DeployerKey.PublicKey(), linkTokenAdminRegistryAccount.Administrator) + + e, err = commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{ + { // accept admin role for tokenAddress + Changeset: commonchangeset.WrapChangeSet(changeset_solana.AcceptAdminRoleTokenAdminRegistry), + Config: changeset_solana.AcceptAdminRoleTokenAdminRegistryConfig{ + ChainSelector: solChain, + TokenPubKey: tokenAddress.String(), + NewRegistryAdminPrivateKey: e.SolChains[solChain].DeployerKey.String(), + }, + }, + }) + require.NoError(t, err) + err = e.SolChains[solChain].GetAccountDataBorshInto(context.Background(), tokenAdminRegistryPDA, &tokenAdminRegistryAccount) + require.NoError(t, err) + // confirm that the administrator is the deployer key + require.Equal(t, e.SolChains[solChain].DeployerKey.PublicKey(), tokenAdminRegistryAccount.Administrator) +} diff --git a/deployment/ccip/changeset/solana/cs_deploy_chain_test.go b/deployment/ccip/changeset/solana/cs_deploy_chain_test.go index 7b5726b61c1..01416f0dd23 100644 --- a/deployment/ccip/changeset/solana/cs_deploy_chain_test.go +++ b/deployment/ccip/changeset/solana/cs_deploy_chain_test.go @@ -34,7 +34,6 @@ func TestDeployChainContractsChangeset(t *testing.T) { selectors = append(selectors, solChainSelectors...) nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) require.NoError(t, err) - p2pIDs := nodes.NonBootstraps().PeerIDs() cfg := make(map[uint64]commontypes.MCMSWithTimelockConfig) contractParams := make(map[uint64]changeset.ChainContractParams) for _, chain := range e.AllChainSelectors() { @@ -67,7 +66,7 @@ func TestDeployChainContractsChangeset(t *testing.T) { RMNDynamicConfig: testhelpers.NewTestRMNDynamicConfig(), NodeOperators: testhelpers.NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From), NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{ - "NodeOperator": p2pIDs, + testhelpers.TestNodeOperator: nodes.NonBootstraps().PeerIDs(), }, }, }, diff --git a/deployment/ccip/changeset/solana/cs_solana_token.go b/deployment/ccip/changeset/solana/cs_solana_token.go index b7a9cb9ca85..e34584a7247 100644 --- a/deployment/ccip/changeset/solana/cs_solana_token.go +++ b/deployment/ccip/changeset/solana/cs_solana_token.go @@ -2,60 +2,57 @@ package solana import ( "context" + "fmt" "github.com/gagliardetto/solana-go" - solRpc "github.com/gagliardetto/solana-go/rpc" "github.com/smartcontractkit/chainlink/deployment" - commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - solCommomUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" solTokenUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/tokens" ) +var _ deployment.ChangeSet[DeploySolanaTokenConfig] = DeploySolanaToken +var _ deployment.ChangeSet[MintSolanaTokenConfig] = MintSolanaToken +var _ deployment.ChangeSet[CreateSolanaTokenATAConfig] = CreateSolanaTokenATA + type DeploySolanaTokenConfig struct { - ChainSelector uint64 - // not sure how to handle this in state - // TODO: figure this out - // Just using this with LinkToken for now - TokenName string + ChainSelector uint64 TokenProgramName string - ATAList []string // addresses to create ATAs for + TokenDecimals uint8 } -var _ deployment.ChangeSet[*DeploySolanaTokenConfig] = DeploySolanaToken - -func DeploySolanaToken(e deployment.Environment, cfg *DeploySolanaTokenConfig) (deployment.ChangesetOutput, error) { - // validate - tokenprogramID, err := deployment.GetTokenProgramID(cfg.TokenProgramName) +func NewTokenInstruction(chain deployment.SolChain, cfg DeploySolanaTokenConfig) ([]solana.Instruction, solana.PrivateKey, error) { + tokenprogramID, err := GetTokenProgramID(cfg.TokenProgramName) if err != nil { - return deployment.ChangesetOutput{}, err + return nil, nil, err } - - chain := e.SolChains[cfg.ChainSelector] - adminPublicKey := chain.DeployerKey.PublicKey() + tokenAdminPubKey := chain.DeployerKey.PublicKey() mint, _ := solana.NewRandomPrivateKey() - // this is the token address - mintPublicKey := mint.PublicKey() - + mintPublicKey := mint.PublicKey() // this is the token address instructions, err := solTokenUtil.CreateToken( - context.Background(), tokenprogramID, mintPublicKey, adminPublicKey, commonchangeset.TokenDecimalsSolana, chain.Client, solRpc.CommitmentConfirmed, + context.Background(), + tokenprogramID, + mintPublicKey, + tokenAdminPubKey, + cfg.TokenDecimals, + chain.Client, + deployment.SolDefaultCommitment, ) if err != nil { - return deployment.ChangesetOutput{}, err + return nil, nil, err } + return instructions, mint, nil +} - // these are associated token accounts for the addresses in the list - // these are the default accounts that created per (token, owner) pair - // hence they are PDAs and dont need to be stored in the address book - for _, ata := range cfg.ATAList { - createATAIx, _, err := solTokenUtil.CreateAssociatedTokenAccount( - tokenprogramID, mintPublicKey, solana.MustPublicKeyFromBase58(ata), adminPublicKey) - if err != nil { - return deployment.ChangesetOutput{}, err - } - instructions = append(instructions, createATAIx) +func DeploySolanaToken(e deployment.Environment, cfg DeploySolanaTokenConfig) (deployment.ChangesetOutput, error) { + chain, ok := e.SolChains[cfg.ChainSelector] + if !ok { + return deployment.ChangesetOutput{}, fmt.Errorf("chain %d not found in environment", cfg.ChainSelector) + } + instructions, mint, err := NewTokenInstruction(chain, cfg) + if err != nil { + return deployment.ChangesetOutput{}, err } err = chain.Confirm(instructions, solCommomUtil.AddSigners(mint)) @@ -64,50 +61,47 @@ func DeploySolanaToken(e deployment.Environment, cfg *DeploySolanaTokenConfig) ( return deployment.ChangesetOutput{}, err } - // address book update newAddresses := deployment.NewMemoryAddressBook() - tv := deployment.NewTypeAndVersion(deployment.ContractType(cfg.TokenName), deployment.Version1_0_0) - err = newAddresses.Save(chain.Selector, mintPublicKey.String(), tv) + tv := deployment.NewTypeAndVersion(deployment.ContractType(cfg.TokenProgramName), deployment.Version1_0_0) + err = newAddresses.Save(cfg.ChainSelector, mint.PublicKey().String(), tv) if err != nil { e.Logger.Errorw("Failed to save link token", "chain", chain.String(), "err", err) return deployment.ChangesetOutput{}, err } - e.Logger.Infow("Deployed contract", "Contract", tv.String(), "addr", mintPublicKey.String(), "chain", chain.String()) + e.Logger.Infow("Deployed contract", "Contract", tv.String(), "addr", mint.PublicKey().String(), "chain", chain.String()) return deployment.ChangesetOutput{ AddressBook: newAddresses, }, nil } +// TODO: there is no validation done around if the token is already deployed +// https://smartcontract-it.atlassian.net/browse/INTAUTO-439 type MintSolanaTokenConfig struct { - ChainSelector uint64 - TokenName string - TokenProgram string - Amount uint64 - ToAddressList []string + ChainSelector uint64 + TokenProgram string + TokenPubkey solana.PublicKey + AmountToAddress map[string]uint64 // address -> amount } -func MintSolanaToken(e deployment.Environment, cfg *MintSolanaTokenConfig) (deployment.ChangesetOutput, error) { +func MintSolanaToken(e deployment.Environment, cfg MintSolanaTokenConfig) (deployment.ChangesetOutput, error) { // get chain chain := e.SolChains[cfg.ChainSelector] // get addresses - tokenAddress, err := deployment.FindTokenAddress(e, cfg.ChainSelector, cfg.TokenName) - if err != nil { - return deployment.ChangesetOutput{}, err - } + tokenAddress := cfg.TokenPubkey // get token program id - tokenprogramID, err := deployment.GetTokenProgramID(cfg.TokenProgram) + tokenprogramID, err := GetTokenProgramID(cfg.TokenProgram) if err != nil { return deployment.ChangesetOutput{}, err } // get mint instructions instructions := []solana.Instruction{} - for _, toAddress := range cfg.ToAddressList { + for toAddress, amount := range cfg.AmountToAddress { toAddressBase58 := solana.MustPublicKeyFromBase58(toAddress) // get associated token account for toAddress ata, _, _ := solTokenUtil.FindAssociatedTokenAddress(tokenprogramID, tokenAddress, toAddressBase58) - mintToI, err := solTokenUtil.MintTo(cfg.Amount, tokenprogramID, tokenAddress, ata, chain.DeployerKey.PublicKey()) + mintToI, err := solTokenUtil.MintTo(amount, tokenprogramID, tokenAddress, ata, chain.DeployerKey.PublicKey()) if err != nil { return deployment.ChangesetOutput{}, err } @@ -121,3 +115,43 @@ func MintSolanaToken(e deployment.Environment, cfg *MintSolanaTokenConfig) (depl } return deployment.ChangesetOutput{}, nil } + +type CreateSolanaTokenATAConfig struct { + ChainSelector uint64 + TokenPubkey solana.PublicKey + TokenProgram string + ATAList []string // addresses to create ATAs for +} + +func CreateSolanaTokenATA(e deployment.Environment, cfg CreateSolanaTokenATAConfig) (deployment.ChangesetOutput, error) { + chain := e.SolChains[cfg.ChainSelector] + + tokenprogramID, err := GetTokenProgramID(cfg.TokenProgram) + if err != nil { + return deployment.ChangesetOutput{}, err + } + + // create instructions for each ATA + instructions := []solana.Instruction{} + for _, ata := range cfg.ATAList { + createATAIx, _, err := solTokenUtil.CreateAssociatedTokenAccount( + tokenprogramID, + cfg.TokenPubkey, + solana.MustPublicKeyFromBase58(ata), + chain.DeployerKey.PublicKey(), + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + instructions = append(instructions, createATAIx) + } + + // confirm instructions + err = chain.Confirm(instructions) + if err != nil { + e.Logger.Errorw("Failed to confirm instructions for ATA creation", "chain", chain.String(), "err", err) + return deployment.ChangesetOutput{}, err + } + + return deployment.ChangesetOutput{}, nil +} diff --git a/deployment/ccip/changeset/solana/cs_solana_token_test.go b/deployment/ccip/changeset/solana/cs_solana_token_test.go index 2fa2887dbbe..67573b20c71 100644 --- a/deployment/ccip/changeset/solana/cs_solana_token_test.go +++ b/deployment/ccip/changeset/solana/cs_solana_token_test.go @@ -4,22 +4,23 @@ import ( "context" "testing" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - "github.com/gagliardetto/solana-go" solRpc "github.com/gagliardetto/solana-go/rpc" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" solTokenUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/tokens" "github.com/smartcontractkit/chainlink/deployment" + ccipChangeset "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" changeset_solana "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/solana" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" + "github.com/smartcontractkit/chainlink/deployment/common/changeset" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/logger" ) -func TestDeploySolanaToken(t *testing.T) { +func TestSolanaTokenOps(t *testing.T) { t.Parallel() lggr := logger.TestLogger(t) e := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{ @@ -29,35 +30,46 @@ func TestDeploySolanaToken(t *testing.T) { e, err := commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{ { Changeset: commonchangeset.WrapChangeSet(changeset_solana.DeploySolanaToken), - Config: &changeset_solana.DeploySolanaTokenConfig{ + Config: changeset_solana.DeploySolanaTokenConfig{ ChainSelector: solChain1, - TokenName: "spl-token-2022", - TokenProgramName: "spl-token-2022", - ATAList: []string{ - e.SolChains[solChain1].DeployerKey.PublicKey().String(), - }, + TokenProgramName: deployment.SPL2022Tokens, + TokenDecimals: 9, + }, + }, + }) + require.NoError(t, err) + + state, err := ccipChangeset.LoadOnchainStateSolana(e) + require.NoError(t, err) + tokenAddress := state.SolChains[solChain1].SPL2022Tokens[0] + testUser, _ := solana.NewRandomPrivateKey() + testUserPubKey := testUser.PublicKey() + + e, err = changeset.ApplyChangesets(t, e, nil, []changeset.ChangesetApplication{ + { + Changeset: changeset.WrapChangeSet(changeset_solana.CreateSolanaTokenATA), + Config: changeset_solana.CreateSolanaTokenATAConfig{ + ChainSelector: solChain1, + TokenPubkey: tokenAddress, + TokenProgram: deployment.SPL2022Tokens, + ATAList: []string{testUserPubKey.String()}, }, }, { Changeset: commonchangeset.WrapChangeSet(changeset_solana.MintSolanaToken), - Config: &changeset_solana.MintSolanaTokenConfig{ + Config: changeset_solana.MintSolanaTokenConfig{ ChainSelector: solChain1, - TokenName: "spl-token-2022", - TokenProgram: "spl-token-2022", - Amount: uint64(1000), - ToAddressList: []string{ - e.SolChains[solChain1].DeployerKey.PublicKey().String(), + TokenPubkey: tokenAddress, + TokenProgram: deployment.SPL2022Tokens, + AmountToAddress: map[string]uint64{ + testUserPubKey.String(): uint64(1000), }, }, }, }) require.NoError(t, err) - // solana test - tokenAddress, err := deployment.FindTokenAddress(e, solChain1, "spl-token-2022") - require.NoError(t, err) - toAddressBase58 := solana.MustPublicKeyFromBase58(e.SolChains[solChain1].DeployerKey.PublicKey().String()) - ata, _, _ := solTokenUtil.FindAssociatedTokenAddress(solana.Token2022ProgramID, tokenAddress, toAddressBase58) + ata, _, _ := solTokenUtil.FindAssociatedTokenAddress(solana.Token2022ProgramID, tokenAddress, testUserPubKey) outDec, outVal, err := solTokenUtil.TokenBalance(context.Background(), e.SolChains[solChain1].Client, ata, solRpc.CommitmentConfirmed) require.NoError(t, err) require.Equal(t, int(1000), outVal) diff --git a/deployment/ccip/changeset/solana_state.go b/deployment/ccip/changeset/solana_state.go index d973c2e44c1..306115d78f2 100644 --- a/deployment/ccip/changeset/solana_state.go +++ b/deployment/ccip/changeset/solana_state.go @@ -1,7 +1,6 @@ package changeset import ( - "encoding/binary" "errors" "fmt" @@ -15,6 +14,8 @@ var ( AddressLookupTable deployment.ContractType = "AddressLookupTable" TokenPool deployment.ContractType = "TokenPool" Receiver deployment.ContractType = "Receiver" + SPL2022Tokens deployment.ContractType = "SPL2022Tokens" + WSOL deployment.ContractType = "WSOL" ) // SolChainState holds a Go binding for all the currently deployed CCIP programs @@ -25,6 +26,9 @@ type SolCCIPChainState struct { Timelock solana.PublicKey AddressLookupTable solana.PublicKey // for chain writer Receiver solana.PublicKey // for tests only + SPL2022Tokens []solana.PublicKey + TokenPool solana.PublicKey + WSOL solana.PublicKey } func LoadOnchainStateSolana(e deployment.Environment) (CCIPOnChainState, error) { @@ -52,6 +56,7 @@ func LoadOnchainStateSolana(e deployment.Environment) (CCIPOnChainState, error) // LoadChainStateSolana Loads all state for a SolChain into state func LoadChainStateSolana(chain deployment.SolChain, addresses map[string]deployment.TypeAndVersion) (SolCCIPChainState, error) { var state SolCCIPChainState + var spl2022Tokens []solana.PublicKey for address, tvStr := range addresses { switch tvStr.String() { case deployment.NewTypeAndVersion(commontypes.LinkToken, deployment.Version1_0_0).String(): @@ -66,108 +71,17 @@ func LoadChainStateSolana(chain deployment.SolChain, addresses map[string]deploy case deployment.NewTypeAndVersion(Receiver, deployment.Version1_0_0).String(): pub := solana.MustPublicKeyFromBase58(address) state.Receiver = pub + case deployment.NewTypeAndVersion(SPL2022Tokens, deployment.Version1_0_0).String(): + pub := solana.MustPublicKeyFromBase58(address) + spl2022Tokens = append(spl2022Tokens, pub) + case deployment.NewTypeAndVersion(TokenPool, deployment.Version1_0_0).String(): + pub := solana.MustPublicKeyFromBase58(address) + state.TokenPool = pub default: return state, fmt.Errorf("unknown contract %s", tvStr) } } + state.WSOL = solana.SolMint + state.SPL2022Tokens = spl2022Tokens return state, nil } - -// GetRouterConfigPDA returns the PDA for the "config" account. -func GetRouterConfigPDA(ccipRouterProgramID solana.PublicKey) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress( - [][]byte{[]byte("config")}, - ccipRouterProgramID, - ) - return pda -} - -// GetRouterStatePDA returns the PDA for the "state" account. -func GetRouterStatePDA(ccipRouterProgramID solana.PublicKey) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress( - [][]byte{[]byte("state")}, - ccipRouterProgramID, - ) - return pda -} - -// GetExternalExecutionConfigPDA returns the PDA for the "external_execution_config" account. -func GetExternalExecutionConfigPDA(ccipRouterProgramID solana.PublicKey) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress( - [][]byte{[]byte("external_execution_config")}, - ccipRouterProgramID, - ) - return pda -} - -// GetExternalTokenPoolsSignerPDA returns the PDA for the "external_token_pools_signer" account. -func GetExternalTokenPoolsSignerPDA(ccipRouterProgramID solana.PublicKey) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress( - [][]byte{[]byte("external_token_pools_signer")}, - ccipRouterProgramID, - ) - return pda -} - -// GetSolanaSourceChainStatePDA returns the PDA for the "source_chain_state" account for Solana. -func GetSolanaSourceChainStatePDA(ccipRouterProgramID solana.PublicKey, solanaChainSelector uint64) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress( - [][]byte{ - []byte("source_chain_state"), - binary.LittleEndian.AppendUint64([]byte{}, solanaChainSelector), - }, - ccipRouterProgramID, - ) - return pda -} - -// GetSolanaDestChainStatePDA returns the PDA for the "dest_chain_state" account for Solana. -func GetSolanaDestChainStatePDA(ccipRouterProgramID solana.PublicKey, solanaChainSelector uint64) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress( - [][]byte{ - []byte("dest_chain_state"), - binary.LittleEndian.AppendUint64([]byte{}, solanaChainSelector), - }, - ccipRouterProgramID, - ) - return pda -} - -// GetEvmSourceChainStatePDA returns the PDA for the "source_chain_state" account for EVM. -func GetEvmSourceChainStatePDA(ccipRouterProgramID solana.PublicKey, evmChainSelector uint64) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress( - [][]byte{ - []byte("source_chain_state"), - binary.LittleEndian.AppendUint64([]byte{}, evmChainSelector), - }, - ccipRouterProgramID, - ) - return pda -} - -// GetEvmDestChainStatePDA returns the PDA for the "dest_chain_state" account for EVM. -func GetEvmDestChainStatePDA(ccipRouterProgramID solana.PublicKey, evmChainSelector uint64) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress( - [][]byte{ - []byte("dest_chain_state"), - binary.LittleEndian.AppendUint64([]byte{}, evmChainSelector), - }, - ccipRouterProgramID, - ) - return pda -} - -func GetReceiverTargetAccountPDA(ccipReceiverProgram solana.PublicKey) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress([][]byte{[]byte("counter")}, ccipReceiverProgram) - return pda -} - -func GetReceiverExternalExecutionConfigPDA(ccipReceiverProgram solana.PublicKey) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress([][]byte{[]byte("external_execution_config")}, ccipReceiverProgram) - return pda -} - -func GetTokenAdminRegistryPDA(ccipRouterProgramID, tokenMint solana.PublicKey) solana.PublicKey { - pda, _, _ := solana.FindProgramAddress([][]byte{[]byte("token_admin_registry"), tokenMint.Bytes()}, ccipRouterProgramID) - return pda -} diff --git a/deployment/ccip/changeset/testhelpers/test_helpers.go b/deployment/ccip/changeset/testhelpers/test_helpers.go index 0ff3a692d08..f394940b802 100644 --- a/deployment/ccip/changeset/testhelpers/test_helpers.go +++ b/deployment/ccip/changeset/testhelpers/test_helpers.go @@ -47,6 +47,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/environment/memory" solRouter "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router" + solState "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/state" solTestConfig "github.com/smartcontractkit/chainlink-ccip/chains/solana/contracts/tests/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_mint_token_pool" @@ -465,7 +466,6 @@ func AddLane( }, } - state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) switch toFamily { @@ -518,13 +518,18 @@ func AddLane( UpdatesByChain: map[uint64]map[uint64]changeset_solana.RemoteChainConfigSolana{ to: { from: { - EnabledAsSource: true, - EnabledAsDestination: true, - RemoteChainOnRampAddress: state.Chains[from].OnRamp.Address().String(), - DefaultTxGasLimit: 1, - MaxPerMsgGasLimit: 100, - MaxDataBytes: 32, - MaxNumberOfTokensPerMsg: 1, + EnabledAsSource: true, + DestinationConfig: solRouter.DestChainConfig{ + IsEnabled: true, + DefaultTxGasLimit: 200000, + MaxPerMsgGasLimit: 3000000, + MaxDataBytes: 30000, + MaxNumberOfTokensPerMsg: 5, + DefaultTokenDestGasOverhead: 5000, + // bytes4(keccak256("CCIP ChainFamilySelector EVM")) + // TODO: do a similar test for other chain families + ChainFamilySelector: [4]uint8{40, 18, 213, 44}, + }, }, }, }, @@ -1359,31 +1364,46 @@ func SavePreloadedSolAddresses(t *testing.T, e deployment.Environment, solChainS err := e.ExistingAddresses.Save(solChainSelector, solTestConfig.CcipRouterProgram.String(), tv) require.NoError(t, err) tv = deployment.NewTypeAndVersion(changeset.Receiver, deployment.Version1_0_0) - err = e.ExistingAddresses.Save(solChainSelector, solTestConfig.CcipReceiverProgram.String(), tv) + err = e.ExistingAddresses.Save(solChainSelector, solTestConfig.CcipLogicReceiver.String(), tv) + require.NoError(t, err) + tv = deployment.NewTypeAndVersion(changeset.TokenPool, deployment.Version1_0_0) + err = e.ExistingAddresses.Save(solChainSelector, solTestConfig.CcipTokenPoolProgram.String(), tv) require.NoError(t, err) } func ValidateSolanaState(t *testing.T, e deployment.Environment, solChainSelectors []uint64) { - solState, err := changeset.LoadOnchainStateSolana(e) - require.NoError(t, err) + state, err := changeset.LoadOnchainStateSolana(e) + require.NoError(t, err, "Failed to load Solana state") + for _, sel := range solChainSelectors { - require.False(t, solState.SolChains[sel].LinkToken.IsZero()) - require.False(t, solState.SolChains[sel].Router.IsZero()) - require.False(t, solState.SolChains[sel].AddressLookupTable.IsZero()) + // Validate chain exists in state + chainState, exists := state.SolChains[sel] + require.True(t, exists, "Chain selector %d not found in Solana state", sel) + + // Validate addresses + require.False(t, chainState.LinkToken.IsZero(), "Link token address is zero for chain %d", sel) + require.False(t, chainState.Router.IsZero(), "Router address is zero for chain %d", sel) + require.False(t, chainState.AddressLookupTable.IsZero(), "Address lookup table is zero for chain %d", sel) + + // Get router config var routerConfigAccount solRouter.Config - err = e.SolChains[sel].GetAccountDataBorshInto(testcontext.Get(t), changeset.GetRouterConfigPDA(solState.SolChains[sel].Router), &routerConfigAccount) - require.NoError(t, err) + configPDA, _, _ := solState.FindConfigPDA(chainState.Router) + + // Check if account exists first + err = e.SolChains[sel].GetAccountDataBorshInto(testcontext.Get(t), configPDA, &routerConfigAccount) + require.NoError(t, err, "Failed to deserialize router config for chain %d", sel) } } func DeploySolanaCcipReceiver(t *testing.T, e deployment.Environment) { state, err := changeset.LoadOnchainStateSolana(e) require.NoError(t, err) - for solSelector, solState := range state.SolChains { - ccip_receiver.SetProgramID(solState.Receiver) + for solSelector, chainState := range state.SolChains { + ccip_receiver.SetProgramID(chainState.Receiver) + externalExecutionConfigPDA, _, _ := solState.FindExternalExecutionConfigPDA(chainState.Receiver) instruction, ixErr := ccip_receiver.NewInitializeInstruction( - changeset.GetReceiverTargetAccountPDA(solState.Receiver), - changeset.GetReceiverExternalExecutionConfigPDA(solState.Receiver), + FindReceiverTargetAccount(chainState.Receiver), + externalExecutionConfigPDA, e.SolChains[solSelector].DeployerKey.PublicKey(), solana.SystemProgramID, ).ValidateAndBuild() @@ -1393,6 +1413,11 @@ func DeploySolanaCcipReceiver(t *testing.T, e deployment.Environment) { } } +func FindReceiverTargetAccount(receiverID solana.PublicKey) solana.PublicKey { + receiverTargetAccount, _, _ := solana.FindProgramAddress([][]byte{[]byte("counter")}, receiverID) + return receiverTargetAccount +} + func GenTestTransferOwnershipConfig( e DeployedEnv, chains []uint64, diff --git a/deployment/common/changeset/deploy_link_token.go b/deployment/common/changeset/deploy_link_token.go index 648401289ff..a87be060a8b 100644 --- a/deployment/common/changeset/deploy_link_token.go +++ b/deployment/common/changeset/deploy_link_token.go @@ -6,11 +6,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/gagliardetto/solana-go" - solRpc "github.com/gagliardetto/solana-go/rpc" chainsel "github.com/smartcontractkit/chain-selectors" solCommomUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" solTokenUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/tokens" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/link_token" @@ -24,7 +24,6 @@ const ( // DeployLinkToken deploys a link token contract to the chain identified by the ChainSelector. func DeployLinkToken(e deployment.Environment, chains []uint64) (deployment.ChangesetOutput, error) { - err := deployment.ValidateSelectorsInEnvironment(e, chains) if err != nil { return deployment.ChangesetOutput{}, err @@ -88,12 +87,17 @@ func deployLinkTokenContractSolana( chain deployment.SolChain, ab deployment.AddressBook, ) error { - adminPublicKey := chain.DeployerKey.PublicKey() + tokenAdminPubKey := chain.DeployerKey.PublicKey() mint, _ := solana.NewRandomPrivateKey() - // this is the token address - mintPublicKey := mint.PublicKey() + mintPublicKey := mint.PublicKey() // this is the token address instructions, err := solTokenUtil.CreateToken( - context.Background(), solana.Token2022ProgramID, mintPublicKey, adminPublicKey, TokenDecimalsSolana, chain.Client, solRpc.CommitmentConfirmed, + context.Background(), + solana.Token2022ProgramID, + mintPublicKey, + tokenAdminPubKey, + TokenDecimalsSolana, + chain.Client, + deployment.SolDefaultCommitment, ) if err != nil { lggr.Errorw("Failed to generate instructions for link token deployment", "chain", chain.String(), "err", err) @@ -105,12 +109,11 @@ func deployLinkTokenContractSolana( return err } tv := deployment.NewTypeAndVersion(types.LinkToken, deployment.Version1_0_0) - lggr.Infow("Deployed contract", "Contract", tv.String(), "addr", mintPublicKey.String(), "chain", chain.String()) - err = ab.Save(chain.Selector, mintPublicKey.String(), tv) + lggr.Infow("Deployed contract", "Contract", tv.String(), "addr", mint.PublicKey().String(), "chain", chain.String()) + err = ab.Save(chain.Selector, mint.PublicKey().String(), tv) if err != nil { lggr.Errorw("Failed to save link token", "chain", chain.String(), "err", err) return err } - return nil } diff --git a/deployment/environment/memory/chain.go b/deployment/environment/memory/chain.go index 020c6df375a..d14be7ba4e7 100644 --- a/deployment/environment/memory/chain.go +++ b/deployment/environment/memory/chain.go @@ -198,7 +198,7 @@ func solChain(t *testing.T, chainID uint64, adminKey *solana.PrivateKey) (string programIds := map[string]string{ "ccip_router": solTestConfig.CcipRouterProgram.String(), "token_pool": solTestConfig.CcipTokenPoolProgram.String(), - "ccip_receiver": solTestConfig.CcipReceiverProgram.String(), + "ccip_receiver": solTestConfig.CcipLogicReceiver.String(), } bcInput := &blockchain.Input{ diff --git a/deployment/go.mod b/deployment/go.mod index 128923e1cf8..990b3e148dd 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -32,7 +32,7 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 - github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b + github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 diff --git a/deployment/go.sum b/deployment/go.sum index d89341fea89..44f19c1c81e 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1396,8 +1396,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= -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-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= +github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= diff --git a/deployment/solana_chain.go b/deployment/solana_chain.go index 53d1adce5bb..1bc643924be 100644 --- a/deployment/solana_chain.go +++ b/deployment/solana_chain.go @@ -18,14 +18,16 @@ import ( solBinary "github.com/gagliardetto/binary" "github.com/gagliardetto/solana-go/rpc" - "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/token_pool" solCommonUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" "github.com/smartcontractkit/chainlink-common/pkg/logger" ) var ( - SolDefaultCommitment = rpc.CommitmentConfirmed - SolDefaultGasLimit = solBinary.Uint128{Lo: 3000, Hi: 0, Endianness: nil} + SolDefaultCommitment = rpc.CommitmentConfirmed + SolDefaultGasLimit = solBinary.Uint128{Lo: 3000, Hi: 0, Endianness: nil} + SolDefaultMaxFeeJuelsPerMsg = solBinary.Uint128{Lo: 300000000, Hi: 0, Endianness: nil} + SPL2022Tokens = "SPL2022Tokens" + SPLTokens = "SPLTokens" ) // SolChain represents a Solana chain. @@ -113,6 +115,14 @@ func (c SolChain) DeployProgram(logger logger.Logger, programName string) (strin return parseProgramID(output) } +func (c SolChain) GetAccountDataBorshInto(ctx context.Context, pubkey solana.PublicKey, accountState interface{}) error { + err := solCommonUtil.GetAccountDataBorshInto(ctx, c.Client, pubkey, SolDefaultCommitment, accountState) + if err != nil { + return err + } + return nil +} + // parseProgramID parses the program ID from the deploy output. func parseProgramID(output string) (string, error) { // Look for the program ID in the CLI output @@ -129,54 +139,3 @@ func parseProgramID(output string) (string, error) { } return output[startIdx : startIdx+endIdx], nil } - -// GetTokenProgramID returns the program ID for the given token program name -func GetTokenProgramID(programName string) (solana.PublicKey, error) { - tokenPrograms := map[string]solana.PublicKey{ - "spl-token": solana.TokenProgramID, - "spl-token-2022": solana.Token2022ProgramID, - } - - programID, ok := tokenPrograms[programName] - if !ok { - return solana.PublicKey{}, fmt.Errorf("invalid token program: %s. Must be one of: spl-token, spl-token-2022", programName) - } - return programID, nil -} - -// GetPoolType returns the token pool type constant for the given string -func GetPoolType(poolType string) (token_pool.PoolType, error) { - poolTypes := map[string]token_pool.PoolType{ - "LockAndRelease": token_pool.LockAndRelease_PoolType, - "BurnAndMint": token_pool.BurnAndMint_PoolType, - } - - poolTypeConstant, ok := poolTypes[poolType] - if !ok { - return 0, fmt.Errorf("invalid pool type: %s. Must be one of: LockAndRelease, BurnAndMint", poolType) - } - return poolTypeConstant, nil -} - -func FindTokenAddress(e Environment, chainSelector uint64, tokenName string) (solana.PublicKey, error) { - addresses, err := e.ExistingAddresses.AddressesForChain(chainSelector) - if err != nil { - return solana.PublicKey{}, err - } - - tv := NewTypeAndVersion(ContractType(tokenName), Version1_0_0) - for address, tvStr := range addresses { - if tvStr.Equal(tv) { - return solana.MustPublicKeyFromBase58(address), nil - } - } - return solana.PublicKey{}, fmt.Errorf("token address not found in address book: %s", tokenName) -} - -func (c SolChain) GetAccountDataBorshInto(ctx context.Context, pubkey solana.PublicKey, accountState interface{}) error { - err := solCommonUtil.GetAccountDataBorshInto(ctx, c.Client, pubkey, SolDefaultCommitment, accountState) - if err != nil { - return err - } - return nil -} diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 7461f115b71..a0f26012169 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -435,7 +435,7 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect - github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect + github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 73fc2ab2ff9..0a2ac5c1be9 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1424,8 +1424,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= -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-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= +github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index ca671e62932..43b95dd009b 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -419,7 +419,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect - github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250103152858-8973fd0c912b // indirect + github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index febcadfabd0..1352a738b7c 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1411,8 +1411,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= -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-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= +github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= From ae3f55b49c159314edb16897540a9ff88d886d0e Mon Sep 17 00:00:00 2001 From: Aleksandr Bukata <96521086+bukata-sa@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:34:59 +0000 Subject: [PATCH 23/43] CCIP-4718 add missing OnRamp cs (#16055) * CCIP-4718 add missing OnRamp cs * lint * lint * lint * lint * fix * fix tests * fix tests * review fixes * review fixes * lint * don't send tx that makes no effect * fix --- .../ccip/changeset/cs_chain_contracts.go | 477 +++++++++++++++--- .../ccip/changeset/cs_chain_contracts_test.go | 262 ++++++++++ .../changeset/solana/cs_chain_contracts.go | 8 +- deployment/ccip/changeset/state.go | 24 + .../changeset/deploy_mcms_with_timelock.go | 2 +- 5 files changed, 707 insertions(+), 66 deletions(-) diff --git a/deployment/ccip/changeset/cs_chain_contracts.go b/deployment/ccip/changeset/cs_chain_contracts.go index f62192b4104..7c2968ff0d1 100644 --- a/deployment/ccip/changeset/cs_chain_contracts.go +++ b/deployment/ccip/changeset/cs_chain_contracts.go @@ -34,6 +34,9 @@ import ( var ( _ deployment.ChangeSet[UpdateOnRampDestsConfig] = UpdateOnRampsDestsChangeset + _ deployment.ChangeSet[UpdateOnRampDynamicConfig] = UpdateOnRampDynamicConfigChangeset + _ deployment.ChangeSet[UpdateOnRampAllowListConfig] = UpdateOnRampAllowListChangeset + _ deployment.ChangeSet[WithdrawOnRampFeeTokensConfig] = WithdrawOnRampFeeTokensChangeset _ deployment.ChangeSet[UpdateOffRampSourcesConfig] = UpdateOffRampSourcesChangeset _ deployment.ChangeSet[UpdateRouterRampsConfig] = UpdateRouterRampsChangeset _ deployment.ChangeSet[UpdateFeeQuoterDestsConfig] = UpdateFeeQuoterDestsChangeset @@ -164,12 +167,12 @@ func UpdateNonceManagersChangeset(e deployment.Environment, cfg UpdateNonceManag if cfg.MCMS == nil { if authTx != nil { if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], authTx, err); err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, nonce_manager.NonceManagerABI) } } if prevRampsTx != nil { if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], prevRampsTx, err); err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, nonce_manager.NonceManagerABI) } } } else { @@ -218,6 +221,12 @@ func UpdateNonceManagersChangeset(e deployment.Environment, cfg UpdateNonceManag }}, nil } +type OnRampDestinationUpdate struct { + IsEnabled bool // If false, disables the destination by setting router to 0x0. + TestRouter bool // Flag for safety only allow specifying either router or testRouter. + AllowListEnabled bool +} + type UpdateOnRampDestsConfig struct { // UpdatesByChain is a mapping of source -> dest -> update. UpdatesByChain map[uint64]map[uint64]OnRampDestinationUpdate @@ -227,12 +236,6 @@ type UpdateOnRampDestsConfig struct { MCMS *MCMSConfig } -type OnRampDestinationUpdate struct { - IsEnabled bool // If false, disables the destination by setting router to 0x0. - TestRouter bool // Flag for safety only allow specifying either router or testRouter. - AllowListEnabled bool -} - func (cfg UpdateOnRampDestsConfig) Validate(e deployment.Environment) error { state, err := LoadOnchainState(e) if err != nil { @@ -240,6 +243,9 @@ func (cfg UpdateOnRampDestsConfig) Validate(e deployment.Environment) error { } supportedChains := state.SupportedChains() for chainSel, updates := range cfg.UpdatesByChain { + if err := ValidateChain(e, state, chainSel, cfg.MCMS != nil); err != nil { + return err + } chainState, ok := state.Chains[chainSel] if !ok { return fmt.Errorf("chain %d not found in onchain state", chainSel) @@ -317,7 +323,7 @@ func UpdateOnRampsDestsChangeset(e deployment.Environment, cfg UpdateOnRampDests } if cfg.MCMS == nil { if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, onramp.OnRampABI) } } else { batches = append(batches, timelock.BatchChainOperation{ @@ -337,7 +343,6 @@ func UpdateOnRampsDestsChangeset(e deployment.Environment, cfg UpdateOnRampDests if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( timelocks, proposers, @@ -353,6 +358,361 @@ func UpdateOnRampsDestsChangeset(e deployment.Environment, cfg UpdateOnRampDests }}, nil } +type OnRampDynamicConfigUpdate struct { + MessageInterceptor common.Address + FeeAggregator common.Address + AllowlistAdmin common.Address +} + +type UpdateOnRampDynamicConfig struct { + // UpdatesByChain is a mapping of source -> update. + UpdatesByChain map[uint64]OnRampDynamicConfigUpdate + // Disallow mixing MCMS/non-MCMS per chain for simplicity. + // (can still be achieved by calling this function multiple times) + MCMS *MCMSConfig +} + +func (cfg UpdateOnRampDynamicConfig) Validate(e deployment.Environment, state CCIPOnChainState) error { + for chainSel, config := range cfg.UpdatesByChain { + if err := ValidateChain(e, state, chainSel, cfg.MCMS != nil); err != nil { + return err + } + if err := commoncs.ValidateOwnership(e.GetContext(), cfg.MCMS != nil, e.Chains[chainSel].DeployerKey.From, state.Chains[chainSel].Timelock.Address(), state.Chains[chainSel].OnRamp); err != nil { + return err + } + if state.Chains[chainSel].FeeQuoter == nil { + return fmt.Errorf("FeeQuoter is not on state of chain %d", chainSel) + } + if config.FeeAggregator == (common.Address{}) { + return fmt.Errorf("FeeAggregator is not specified for chain %d", chainSel) + } + } + return nil +} + +func UpdateOnRampDynamicConfigChangeset(e deployment.Environment, cfg UpdateOnRampDynamicConfig) (deployment.ChangesetOutput, error) { + state, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if err := cfg.Validate(e, state); err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for chainSel, update := range cfg.UpdatesByChain { + txOps := e.Chains[chainSel].DeployerKey + if cfg.MCMS != nil { + txOps = deployment.SimTransactOpts() + } + onRamp := state.Chains[chainSel].OnRamp + dynamicConfig, err := onRamp.GetDynamicConfig(nil) + if err != nil { + return deployment.ChangesetOutput{}, err + } + // Do not update dynamic config if it is already in desired state + if dynamicConfig.FeeQuoter == state.Chains[chainSel].FeeQuoter.Address() && + dynamicConfig.MessageInterceptor == update.MessageInterceptor && + dynamicConfig.FeeAggregator == update.FeeAggregator && + dynamicConfig.AllowlistAdmin == update.AllowlistAdmin { + continue + } + tx, err := onRamp.SetDynamicConfig(txOps, onramp.OnRampDynamicConfig{ + FeeQuoter: state.Chains[chainSel].FeeQuoter.Address(), + ReentrancyGuardEntered: false, + MessageInterceptor: update.MessageInterceptor, + FeeAggregator: update.FeeAggregator, + AllowlistAdmin: update.AllowlistAdmin, + }) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, onramp.OnRampABI) + } + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chainSel), + Batch: []mcms.Operation{ + { + To: onRamp.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + proposal, err := proposalutils.BuildProposalFromBatches( + timelocks, proposers, batches, + "update onramp dynamic config", + cfg.MCMS.MinDelay) + if err != nil { + return deployment.ChangesetOutput{}, err + } + return deployment.ChangesetOutput{ + Proposals: []timelock.MCMSWithTimelockProposal{*proposal}, + }, nil +} + +type OnRampAllowListUpdate struct { + AllowListEnabled bool + AddedAllowlistedSenders []common.Address + RemovedAllowlistedSenders []common.Address +} + +type UpdateOnRampAllowListConfig struct { + // UpdatesByChain is a mapping of source -> dest -> update. + UpdatesByChain map[uint64]map[uint64]OnRampAllowListUpdate + // Disallow mixing MCMS/non-MCMS per chain for simplicity. + // (can still be achieved by calling this function multiple times) + MCMS *MCMSConfig +} + +func (cfg UpdateOnRampAllowListConfig) Validate(env deployment.Environment) error { + state, err := LoadOnchainState(env) + if err != nil { + return fmt.Errorf("failed to load onchain state: %w", err) + } + for srcSel, updates := range cfg.UpdatesByChain { + if err := ValidateChain(env, state, srcSel, cfg.MCMS != nil); err != nil { + return err + } + onRamp := state.Chains[srcSel].OnRamp + if onRamp == nil { + return fmt.Errorf("missing onRamp on %d", srcSel) + } + config, err := onRamp.GetDynamicConfig(nil) + if err != nil { + return err + } + owner, err := onRamp.Owner(nil) + if err != nil { + return fmt.Errorf("failed to get owner: %w", err) + } + var signer common.Address + if cfg.MCMS == nil { + signer = env.Chains[srcSel].DeployerKey.From + if signer != config.AllowlistAdmin && signer != owner { + return fmt.Errorf("deployer key is not onramp's %s owner nor allowlist admin", onRamp.Address()) + } + } else { + signer = state.Chains[srcSel].Timelock.Address() + if signer != config.AllowlistAdmin && signer != owner { + return fmt.Errorf("timelock is not onramp's %s owner nor allowlist admin", onRamp.Address()) + } + } + for destSel, update := range updates { + if err := ValidateChain(env, state, srcSel, false); err != nil { + return err + } + if len(update.AddedAllowlistedSenders) > 0 && !update.AllowListEnabled { + return fmt.Errorf("can't allowlist senders with disabled allowlist for src=%d, dest=%d", srcSel, destSel) + } + for _, sender := range update.AddedAllowlistedSenders { + if sender == (common.Address{}) { + return fmt.Errorf("can't allowlist 0-address sender for src=%d, dest=%d", srcSel, destSel) + } + } + } + } + return nil +} + +func UpdateOnRampAllowListChangeset(e deployment.Environment, cfg UpdateOnRampAllowListConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + onchain, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for srcSel, updates := range cfg.UpdatesByChain { + txOps := e.Chains[srcSel].DeployerKey + if cfg.MCMS != nil { + txOps = deployment.SimTransactOpts() + } + onRamp := onchain.Chains[srcSel].OnRamp + args := make([]onramp.OnRampAllowlistConfigArgs, len(updates)) + for destSel, update := range updates { + allowedSendersResp, err := onRamp.GetAllowedSendersList(nil, destSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if allowedSendersResp.IsEnabled == update.AllowListEnabled { + desiredState := make(map[common.Address]bool) + for _, address := range update.AddedAllowlistedSenders { + desiredState[address] = true + } + for _, address := range update.RemovedAllowlistedSenders { + desiredState[address] = false + } + needUpdate := false + for _, allowedSender := range allowedSendersResp.ConfiguredAddresses { + if !desiredState[allowedSender] { + needUpdate = true + } + } + if !needUpdate { + continue + } + } + args = append(args, onramp.OnRampAllowlistConfigArgs{ + DestChainSelector: destSel, + AllowlistEnabled: update.AllowListEnabled, + AddedAllowlistedSenders: update.AddedAllowlistedSenders, + RemovedAllowlistedSenders: update.RemovedAllowlistedSenders, + }) + } + if len(args) == 0 { + continue + } + tx, err := onRamp.ApplyAllowlistUpdates(txOps, args) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[srcSel], tx, err); err != nil { + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, onramp.OnRampABI) + } + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(srcSel), + Batch: []mcms.Operation{ + { + To: onRamp.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[srcSel] = onchain.Chains[srcSel].Timelock.Address() + proposers[srcSel] = onchain.Chains[srcSel].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + proposal, err := proposalutils.BuildProposalFromBatches( + timelocks, + proposers, + batches, + "update onramp allowlist", + cfg.MCMS.MinDelay, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + return deployment.ChangesetOutput{ + Proposals: []timelock.MCMSWithTimelockProposal{*proposal}, + }, nil +} + +type WithdrawOnRampFeeTokensConfig struct { + FeeTokensByChain map[uint64][]common.Address + MCMS *MCMSConfig +} + +func (cfg WithdrawOnRampFeeTokensConfig) Validate(e deployment.Environment, state CCIPOnChainState) error { + for chainSel, feeTokens := range cfg.FeeTokensByChain { + if err := ValidateChain(e, state, chainSel, cfg.MCMS != nil); err != nil { + return err + } + if err := commoncs.ValidateOwnership(e.GetContext(), cfg.MCMS != nil, e.Chains[chainSel].DeployerKey.From, state.Chains[chainSel].Timelock.Address(), state.Chains[chainSel].OnRamp); err != nil { + return err + } + feeQuoter := state.Chains[chainSel].FeeQuoter + if feeQuoter == nil { + return fmt.Errorf("no fee quoter for chain %d", chainSel) + } + onchainFeeTokens, err := feeQuoter.GetFeeTokens(nil) + if len(onchainFeeTokens) == 0 { + return fmt.Errorf("no fee tokens configured on fee quoter %s for chain %d", feeQuoter.Address().Hex(), chainSel) + } + if err != nil { + return err + } + for _, feeToken := range feeTokens { + found := false + for _, onchainFeeToken := range onchainFeeTokens { + if onchainFeeToken == feeToken { + found = true + break + } + } + if !found { + return fmt.Errorf("unknown fee token address=%s on chain=%d", feeToken.Hex(), chainSel) + } + } + } + return nil +} + +func WithdrawOnRampFeeTokensChangeset(e deployment.Environment, cfg WithdrawOnRampFeeTokensConfig) (deployment.ChangesetOutput, error) { + state, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if err := cfg.Validate(e, state); err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for chainSel, feeTokens := range cfg.FeeTokensByChain { + txOps := e.Chains[chainSel].DeployerKey + onRamp := state.Chains[chainSel].OnRamp + tx, err := onRamp.WithdrawFeeTokens(txOps, feeTokens) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, onramp.OnRampABI) + } + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chainSel), + Batch: []mcms.Operation{ + { + To: onRamp.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + proposal, err := proposalutils.BuildProposalFromBatches( + timelocks, + proposers, + batches, + "withdraw onramp fee tokens", + cfg.MCMS.MinDelay, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + return deployment.ChangesetOutput{ + Proposals: []timelock.MCMSWithTimelockProposal{*proposal}, + }, nil +} + type UpdateFeeQuoterPricesConfig struct { PricesByChain map[uint64]FeeQuoterPriceUpdatePerSource // source -> PriceDetails MCMS *MCMSConfig @@ -478,7 +838,8 @@ func UpdateFeeQuoterPricesChangeset(e deployment.Environment, cfg UpdateFeeQuote } if cfg.MCMS == nil { if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("error confirming transaction for chain %s: %w", e.Chains[chainSel].String(), err) + decodedErr := deployment.DecodedErrFromABIIfDataErr(err, fee_quoter.FeeQuoterABI) + return deployment.ChangesetOutput{}, fmt.Errorf("error confirming transaction for chain %s: %w", e.Chains[chainSel].String(), decodedErr) } } else { batches = append(batches, timelock.BatchChainOperation{ @@ -594,7 +955,7 @@ func UpdateFeeQuoterDestsChangeset(e deployment.Environment, cfg UpdateFeeQuoter } if cfg.MCMS == nil { if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, fee_quoter.FeeQuoterABI) } } else { batches = append(batches, timelock.BatchChainOperation{ @@ -630,6 +991,11 @@ func UpdateFeeQuoterDestsChangeset(e deployment.Environment, cfg UpdateFeeQuoter }}, nil } +type OffRampSourceUpdate struct { + IsEnabled bool // If false, disables the source by setting router to 0x0. + TestRouter bool // Flag for safety only allow specifying either router or testRouter. +} + type UpdateOffRampSourcesConfig struct { // UpdatesByChain is a mapping from dest chain -> source chain -> source chain // update on the dest chain offramp. @@ -637,16 +1003,7 @@ type UpdateOffRampSourcesConfig struct { MCMS *MCMSConfig } -type OffRampSourceUpdate struct { - IsEnabled bool // If false, disables the source by setting router to 0x0. - TestRouter bool // Flag for safety only allow specifying either router or testRouter. -} - -func (cfg UpdateOffRampSourcesConfig) Validate(e deployment.Environment) error { - state, err := LoadOnchainState(e) - if err != nil { - return err - } +func (cfg UpdateOffRampSourcesConfig) Validate(e deployment.Environment, state CCIPOnChainState) error { supportedChains := state.SupportedChains() for chainSel, updates := range cfg.UpdatesByChain { chainState, ok := state.Chains[chainSel] @@ -688,11 +1045,11 @@ func (cfg UpdateOffRampSourcesConfig) Validate(e deployment.Environment) 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 { + state, err := LoadOnchainState(e) + if err != nil { return deployment.ChangesetOutput{}, err } - s, err := LoadOnchainState(e) - if err != nil { + if err := cfg.Validate(e, state); err != nil { return deployment.ChangesetOutput{}, err } var batches []timelock.BatchChainOperation @@ -704,16 +1061,16 @@ func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSo if cfg.MCMS != nil { txOpts = deployment.SimTransactOpts() } - offRamp := s.Chains[chainSel].OffRamp + offRamp := state.Chains[chainSel].OffRamp var args []offramp.OffRampSourceChainConfigArgs for source, update := range updates { router := common.HexToAddress("0x0") if update.TestRouter { - router = s.Chains[chainSel].TestRouter.Address() + router = state.Chains[chainSel].TestRouter.Address() } else { - router = s.Chains[chainSel].Router.Address() + router = state.Chains[chainSel].Router.Address() } - onRamp := s.Chains[source].OnRamp + onRamp := state.Chains[source].OnRamp args = append(args, offramp.OffRampSourceChainConfigArgs{ SourceChainSelector: source, Router: router, @@ -727,7 +1084,7 @@ func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSo } if cfg.MCMS == nil { if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, offramp.OffRampABI) } } else { batches = append(batches, timelock.BatchChainOperation{ @@ -740,8 +1097,8 @@ func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSo }, }, }) - timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() - proposers[chainSel] = s.Chains[chainSel].ProposerMcm + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm } } if cfg.MCMS == nil { @@ -763,6 +1120,11 @@ func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSo }}, nil } +type RouterUpdates struct { + OffRampUpdates map[uint64]bool + OnRampUpdates map[uint64]bool +} + type UpdateRouterRampsConfig struct { // TestRouter means the updates will be applied to the test router // on all chains. Disallow mixing test router/non-test router per chain for simplicity. @@ -771,18 +1133,12 @@ type UpdateRouterRampsConfig struct { MCMS *MCMSConfig } -type RouterUpdates struct { - OffRampUpdates map[uint64]bool - OnRampUpdates map[uint64]bool -} - -func (cfg UpdateRouterRampsConfig) Validate(e deployment.Environment) error { - state, err := LoadOnchainState(e) - if err != nil { - return err - } +func (cfg UpdateRouterRampsConfig) Validate(e deployment.Environment, state CCIPOnChainState) error { supportedChains := state.SupportedChains() for chainSel, update := range cfg.UpdatesByChain { + if err := ValidateChain(e, state, chainSel, cfg.MCMS != nil); err != nil { + return err + } chainState, ok := state.Chains[chainSel] if !ok { return fmt.Errorf("chain %d not found in onchain state", chainSel) @@ -845,11 +1201,11 @@ func (cfg UpdateRouterRampsConfig) Validate(e deployment.Environment) error { // on all chains to support the new chain through the test router first. Once tested, // Enable the new destination on the real router. func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsConfig) (deployment.ChangesetOutput, error) { - if err := cfg.Validate(e); err != nil { + state, err := LoadOnchainState(e) + if err != nil { return deployment.ChangesetOutput{}, err } - s, err := LoadOnchainState(e) - if err != nil { + if err := cfg.Validate(e, state); err != nil { return deployment.ChangesetOutput{}, err } var batches []timelock.BatchChainOperation @@ -861,14 +1217,14 @@ func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsC if cfg.MCMS != nil { txOpts = deployment.SimTransactOpts() } - routerC := s.Chains[chainSel].Router + routerC := state.Chains[chainSel].Router if cfg.TestRouter { - routerC = s.Chains[chainSel].TestRouter + routerC = state.Chains[chainSel].TestRouter } // Note if we add distinct offramps per source to the state, // we'll need to add support here for looking them up. // For now its simple, all sources use the same offramp. - offRamp := s.Chains[chainSel].OffRamp + offRamp := state.Chains[chainSel].OffRamp var removes, adds []router.RouterOffRamp for source, enabled := range update.OffRampUpdates { if enabled { @@ -884,7 +1240,7 @@ func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsC } } // Ditto here, only one onramp expected until 1.7. - onRamp := s.Chains[chainSel].OnRamp + onRamp := state.Chains[chainSel].OnRamp var onRampUpdates []router.RouterOnRamp for dest, enabled := range update.OnRampUpdates { if enabled { @@ -905,7 +1261,7 @@ func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsC } if cfg.MCMS == nil { if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, router.RouterABI) } } else { batches = append(batches, timelock.BatchChainOperation{ @@ -918,8 +1274,8 @@ func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsC }, }, }) - timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() - proposers[chainSel] = s.Chains[chainSel].ProposerMcm + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm } } if cfg.MCMS == nil { @@ -948,14 +1304,13 @@ type SetOCR3OffRampConfig struct { MCMS *MCMSConfig } -func (c SetOCR3OffRampConfig) Validate(e deployment.Environment) error { - state, err := LoadOnchainState(e) - if err != nil { - return err - } +func (c SetOCR3OffRampConfig) Validate(e deployment.Environment, state CCIPOnChainState) error { if _, ok := state.Chains[c.HomeChainSel]; !ok { return fmt.Errorf("home chain %d not found in onchain state", c.HomeChainSel) } + if err := ValidateChain(e, state, c.HomeChainSel, c.MCMS != nil); err != nil { + return err + } if c.CCIPHomeConfigType != globals.ConfigTypeActive && c.CCIPHomeConfigType != globals.ConfigTypeCandidate { return fmt.Errorf("invalid CCIPHomeConfigType should be either %s or %s", globals.ConfigTypeActive, globals.ConfigTypeCandidate) @@ -1005,13 +1360,13 @@ func (c SetOCR3OffRampConfig) validateRemoteChain(e *deployment.Environment, sta // Multichain is especially helpful for NOP rotations where we have // to touch all the chain to change signers. func SetOCR3OffRampChangeset(e deployment.Environment, cfg SetOCR3OffRampConfig) (deployment.ChangesetOutput, error) { - if err := cfg.Validate(e); err != nil { - return deployment.ChangesetOutput{}, err - } state, err := LoadOnchainState(e) if err != nil { return deployment.ChangesetOutput{}, err } + if err := cfg.Validate(e, state); err != nil { + return deployment.ChangesetOutput{}, err + } var batches []timelock.BatchChainOperation timelocks := make(map[uint64]common.Address) proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) @@ -1047,7 +1402,7 @@ func SetOCR3OffRampChangeset(e deployment.Environment, cfg SetOCR3OffRampConfig) } if cfg.MCMS == nil { if _, err := deployment.ConfirmIfNoError(e.Chains[remote], tx, err); err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, offramp.OffRampABI) } } else { batches = append(batches, timelock.BatchChainOperation{ diff --git a/deployment/ccip/changeset/cs_chain_contracts_test.go b/deployment/ccip/changeset/cs_chain_contracts_test.go index ea91f81aeba..c6b6ebb5585 100644 --- a/deployment/ccip/changeset/cs_chain_contracts_test.go +++ b/deployment/ccip/changeset/cs_chain_contracts_test.go @@ -1,10 +1,12 @@ package changeset_test import ( + "math/big" "testing" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" @@ -93,6 +95,266 @@ func TestUpdateOnRampsDests(t *testing.T) { } } +func TestUpdateOnRampDynamicConfig(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := testcontext.Get(t) + // Default env just has 2 chains with all contracts + // deployed but no lanes. + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + var mcmsConfig *changeset.MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &changeset.MCMSConfig{ + MinDelay: 0, + } + } + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampDynamicConfigChangeset), + Config: changeset.UpdateOnRampDynamicConfig{ + UpdatesByChain: map[uint64]changeset.OnRampDynamicConfigUpdate{ + source: { + FeeAggregator: common.HexToAddress("0x1002"), + }, + dest: { + FeeAggregator: common.HexToAddress("0x2002"), + }, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + // Assert the onramp configuration is as we expect. + sourceCfg, err := state.Chains[source].OnRamp.GetDynamicConfig(&bind.CallOpts{Context: ctx}) + require.NoError(t, err) + require.Equal(t, state.Chains[source].FeeQuoter.Address(), sourceCfg.FeeQuoter) + require.Equal(t, common.HexToAddress("0x1002"), sourceCfg.FeeAggregator) + destCfg, err := state.Chains[dest].OnRamp.GetDynamicConfig(&bind.CallOpts{Context: ctx}) + require.NoError(t, err) + require.Equal(t, state.Chains[dest].FeeQuoter.Address(), destCfg.FeeQuoter) + require.Equal(t, common.HexToAddress("0x2002"), destCfg.FeeAggregator) + }) + } +} + +func TestUpdateOnRampAllowList(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := testcontext.Get(t) + // Default env just has 2 chains with all contracts + // deployed but no lanes. + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + var mcmsConfig *changeset.MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &changeset.MCMSConfig{ + MinDelay: 0, + } + } + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampAllowListChangeset), + Config: changeset.UpdateOnRampAllowListConfig{ + UpdatesByChain: map[uint64]map[uint64]changeset.OnRampAllowListUpdate{ + source: { + dest: { + AllowListEnabled: true, + AddedAllowlistedSenders: []common.Address{common.HexToAddress("0x1001"), common.HexToAddress("0x1002")}, + RemovedAllowlistedSenders: []common.Address{common.HexToAddress("0x1002"), common.HexToAddress("0x1003")}, + }, + }, + dest: { + source: { + AllowListEnabled: true, + AddedAllowlistedSenders: []common.Address{common.HexToAddress("0x2001"), common.HexToAddress("0x2002")}, + RemovedAllowlistedSenders: []common.Address{common.HexToAddress("0x2002"), common.HexToAddress("0x2003")}, + }, + }, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + // Assert the onramp configuration is as we expect. + sourceCfg, err := state.Chains[source].OnRamp.GetAllowedSendersList(&bind.CallOpts{Context: ctx}, dest) + require.NoError(t, err) + require.Contains(t, sourceCfg.ConfiguredAddresses, common.HexToAddress("0x1001")) + require.True(t, sourceCfg.IsEnabled) + destCfg, err := state.Chains[dest].OnRamp.GetAllowedSendersList(&bind.CallOpts{Context: ctx}, source) + require.NoError(t, err) + require.Contains(t, destCfg.ConfiguredAddresses, common.HexToAddress("0x2001")) + require.True(t, destCfg.IsEnabled) + }) + } +} + +func TestWithdrawOnRampFeeTokens(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := testcontext.Get(t) + // Default env just has 2 chains with all contracts + // deployed but no lanes. + tenv, _ := testhelpers.NewMemoryEnvironment(t) + state, err := changeset.LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + + require.NotNil(t, state.Chains[source].ProposerMcm) + require.NotNil(t, state.Chains[dest].ProposerMcm) + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + var mcmsConfig *changeset.MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &changeset.MCMSConfig{ + MinDelay: 0, + } + } + + linkToken := state.Chains[source].LinkToken + require.NotNil(t, linkToken) + weth9 := state.Chains[source].Weth9 + require.NotNil(t, weth9) + + // mint some Link and deposit Weth9 to onramp on source chain + tokenAmount := big.NewInt(100) + onRamp := state.Chains[source].OnRamp + config, err := onRamp.GetDynamicConfig(&bind.CallOpts{Context: ctx}) + require.NoError(t, err) + feeAgggregator := config.FeeAggregator + deployer := tenv.Env.Chains[source].DeployerKey + + // LINK + tx, err := linkToken.GrantMintRole(deployer, feeAgggregator) + require.NoError(t, err) + _, err = tenv.Env.Chains[source].Confirm(tx) + require.NoError(t, err) + tx, err = linkToken.Mint(deployer, onRamp.Address(), tokenAmount) + require.NoError(t, err) + _, err = tenv.Env.Chains[source].Confirm(tx) + require.NoError(t, err) + + // WETH9 + txOpts := *tenv.Env.Chains[source].DeployerKey + txOpts.Value = tokenAmount + tx, err = weth9.Deposit(&txOpts) + require.NoError(t, err) + _, err = tenv.Env.Chains[source].Confirm(tx) + require.NoError(t, err) + tx, err = weth9.Transfer(deployer, onRamp.Address(), tokenAmount) + require.NoError(t, err) + _, err = tenv.Env.Chains[source].Confirm(tx) + require.NoError(t, err) + + // check init balances + aggregatorInitLinks, err := linkToken.BalanceOf(&bind.CallOpts{Context: ctx}, feeAgggregator) + require.NoError(t, err) + require.Equal(t, int64(0), aggregatorInitLinks.Int64()) + aggregatorInitWeth, err := weth9.BalanceOf(&bind.CallOpts{Context: ctx}, feeAgggregator) + require.NoError(t, err) + require.Equal(t, int64(0), aggregatorInitWeth.Int64()) + + onRampInitLinks, err := linkToken.BalanceOf(&bind.CallOpts{Context: ctx}, onRamp.Address()) + require.NoError(t, err) + require.Equal(t, tokenAmount, onRampInitLinks) + onRampInitWeth, err := weth9.BalanceOf(&bind.CallOpts{Context: ctx}, onRamp.Address()) + require.NoError(t, err) + require.Equal(t, tokenAmount, onRampInitWeth) + + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(changeset.WithdrawOnRampFeeTokensChangeset), + Config: changeset.WithdrawOnRampFeeTokensConfig{ + FeeTokensByChain: map[uint64][]common.Address{ + source: {linkToken.Address(), weth9.Address()}, + dest: {state.Chains[dest].LinkToken.Address(), state.Chains[dest].Weth9.Address()}, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + // Assert that feeAggregator receives all fee tokens from OnRamp + aggregatorLinks, err := linkToken.BalanceOf(&bind.CallOpts{Context: ctx}, feeAgggregator) + require.NoError(t, err) + assert.Equal(t, tokenAmount, aggregatorLinks) + aggregatorWeth, err := weth9.BalanceOf(&bind.CallOpts{Context: ctx}, feeAgggregator) + require.NoError(t, err) + assert.Equal(t, tokenAmount, aggregatorWeth) + }) + } +} + func TestUpdateOffRampsSources(t *testing.T) { for _, tc := range []struct { name string diff --git a/deployment/ccip/changeset/solana/cs_chain_contracts.go b/deployment/ccip/changeset/solana/cs_chain_contracts.go index b87cc284421..59ec483feb4 100644 --- a/deployment/ccip/changeset/solana/cs_chain_contracts.go +++ b/deployment/ccip/changeset/solana/cs_chain_contracts.go @@ -255,14 +255,14 @@ func btoi(b bool) uint8 { // Multichain is especially helpful for NOP rotations where we have // to touch all the chain to change signers. func SetOCR3ConfigSolana(e deployment.Environment, cfg cs.SetOCR3OffRampConfig) (deployment.ChangesetOutput, error) { - if err := cfg.Validate(e); err != nil { - return deployment.ChangesetOutput{}, err - } - state, err := cs.LoadOnchainState(e) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } + + if err := cfg.Validate(e, state); err != nil { + return deployment.ChangesetOutput{}, err + } solChains := state.SolChains // cfg.RemoteChainSels will be a bunch of solana chains diff --git a/deployment/ccip/changeset/state.go b/deployment/ccip/changeset/state.go index 012a4eddf99..739333b720b 100644 --- a/deployment/ccip/changeset/state.go +++ b/deployment/ccip/changeset/state.go @@ -836,3 +836,27 @@ func (s CCIPOnChainState) ValidateOffRamp(chainSelector uint64) error { } return nil } + +func ValidateChain(env deployment.Environment, state CCIPOnChainState, chainSel uint64, checkMcms bool) error { + err := deployment.IsValidChainSelector(chainSel) + if err != nil { + return fmt.Errorf("is not valid chain selector %d: %w", chainSel, err) + } + chain, ok := env.Chains[chainSel] + if !ok { + return fmt.Errorf("chain with selector %d does not exist in environment", chainSel) + } + chainState, ok := state.Chains[chainSel] + if !ok { + return fmt.Errorf("%s does not exist in state", chain) + } + if checkMcms { + if chainState.Timelock == nil { + return fmt.Errorf("missing timelock on %s", chain) + } + if chainState.ProposerMcm == nil { + return fmt.Errorf("missing proposerMcm on %s", chain) + } + } + return nil +} diff --git a/deployment/common/changeset/deploy_mcms_with_timelock.go b/deployment/common/changeset/deploy_mcms_with_timelock.go index a04065de741..10a48b0b22b 100644 --- a/deployment/common/changeset/deploy_mcms_with_timelock.go +++ b/deployment/common/changeset/deploy_mcms_with_timelock.go @@ -33,7 +33,7 @@ func ValidateOwnership(ctx context.Context, mcms bool, deployerKey, timelock com return fmt.Errorf("failed to get owner: %w", err) } if mcms && owner != timelock { - return fmt.Errorf("%s not owned by deployer key", contract.Address()) + return fmt.Errorf("%s not owned by timelock", contract.Address()) } else if !mcms && owner != deployerKey { return fmt.Errorf("%s not owned by deployer key", contract.Address()) } From 212ec7e02c03db61f4c65106eb4aa117d322594b Mon Sep 17 00:00:00 2001 From: Matthew Pendrey Date: Fri, 31 Jan 2025 14:20:22 +0000 Subject: [PATCH 24/43] shutdown context change (#16167) --- core/capabilities/integration_tests/framework/fake_libocr.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/capabilities/integration_tests/framework/fake_libocr.go b/core/capabilities/integration_tests/framework/fake_libocr.go index 0f378a39129..12ba070bc48 100644 --- a/core/capabilities/integration_tests/framework/fake_libocr.go +++ b/core/capabilities/integration_tests/framework/fake_libocr.go @@ -182,7 +182,9 @@ func (m *FakeLibOCR) Start(ctx context.Context) error { case <-ctx.Done(): return case <-ticker.C: - err := m.simulateProtocolRound(ctx) + serviceCtx, cancel := m.stopCh.NewCtx() + err := m.simulateProtocolRound(serviceCtx) + cancel() if err != nil { m.lggr.Errorf("simulating protocol round: %v", err) } From 63092e424cfea6ae17f670a6a83a00c95966ddb2 Mon Sep 17 00:00:00 2001 From: "Simon B.Robert" Date: Fri, 31 Jan 2025 09:55:49 -0500 Subject: [PATCH 25/43] Improve deployer group (#16126) * Improve deployer group - Increase coverage for deployer group test - Add mutli proposal support * Update deployment/ccip/changeset/deployer_group.go Co-authored-by: kylesmartin <54827727+kylesmartin@users.noreply.github.com> * Address PR comments * Fix liniting issues --------- Co-authored-by: kylesmartin <54827727+kylesmartin@users.noreply.github.com> --- .../ccip/changeset/cs_accept_admin_role.go | 5 +- .../changeset/cs_configure_token_pools.go | 5 +- .../ccip/changeset/cs_propose_admin_role.go | 5 +- .../ccip/changeset/cs_rmn_curse_uncurse.go | 10 +- deployment/ccip/changeset/cs_set_pool.go | 5 +- .../ccip/changeset/cs_transfer_admin_role.go | 5 +- .../ccip/changeset/cs_update_rmn_config.go | 10 +- deployment/ccip/changeset/deployer_group.go | 216 ++++++++++++---- .../ccip/changeset/deployer_group_test.go | 243 +++++++++++++++++- 9 files changed, 433 insertions(+), 71 deletions(-) diff --git a/deployment/ccip/changeset/cs_accept_admin_role.go b/deployment/ccip/changeset/cs_accept_admin_role.go index 68ce58518bf..98c103b5826 100644 --- a/deployment/ccip/changeset/cs_accept_admin_role.go +++ b/deployment/ccip/changeset/cs_accept_admin_role.go @@ -34,7 +34,8 @@ func AcceptAdminRoleChangeset(env deployment.Environment, c TokenAdminRegistryCh if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(env, state, c.MCMS) + + deployerGroup := NewDeployerGroup(env, state, c.MCMS).WithDeploymentContext("accept admin role for tokens on token admin registries") for chainSelector, tokenSymbolToPoolInfo := range c.Pools { chain := env.Chains[chainSelector] @@ -55,5 +56,5 @@ func AcceptAdminRoleChangeset(env deployment.Environment, c TokenAdminRegistryCh } } - return deployerGroup.Enact("accept admin role for tokens on token admin registries") + return deployerGroup.Enact() } diff --git a/deployment/ccip/changeset/cs_configure_token_pools.go b/deployment/ccip/changeset/cs_configure_token_pools.go index bbddfaa43c2..bdf4072030a 100644 --- a/deployment/ccip/changeset/cs_configure_token_pools.go +++ b/deployment/ccip/changeset/cs_configure_token_pools.go @@ -173,7 +173,8 @@ func ConfigureTokenPoolContractsChangeset(env deployment.Environment, c Configur if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(env, state, c.MCMS) + + deployerGroup := NewDeployerGroup(env, state, c.MCMS).WithDeploymentContext(fmt.Sprintf("configure %s token pools", c.TokenSymbol)) for chainSelector := range c.PoolUpdates { chain := env.Chains[chainSelector] @@ -188,7 +189,7 @@ func ConfigureTokenPoolContractsChangeset(env deployment.Environment, c Configur } } - return deployerGroup.Enact(fmt.Sprintf("configure %s token pools", c.TokenSymbol)) + return deployerGroup.Enact() } // configureTokenPool creates all transactions required to configure the desired token pool on a chain, diff --git a/deployment/ccip/changeset/cs_propose_admin_role.go b/deployment/ccip/changeset/cs_propose_admin_role.go index b6db1b0611d..231a8e5c4c9 100644 --- a/deployment/ccip/changeset/cs_propose_admin_role.go +++ b/deployment/ccip/changeset/cs_propose_admin_role.go @@ -38,7 +38,8 @@ func ProposeAdminRoleChangeset(env deployment.Environment, c TokenAdminRegistryC if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(env, state, c.MCMS) + + deployerGroup := NewDeployerGroup(env, state, c.MCMS).WithDeploymentContext("propose admin role for tokens on token admin registries") for chainSelector, tokenSymbolToPoolInfo := range c.Pools { chain := env.Chains[chainSelector] @@ -66,5 +67,5 @@ func ProposeAdminRoleChangeset(env deployment.Environment, c TokenAdminRegistryC } } - return deployerGroup.Enact("propose admin role for tokens on token admin registries") + return deployerGroup.Enact() } diff --git a/deployment/ccip/changeset/cs_rmn_curse_uncurse.go b/deployment/ccip/changeset/cs_rmn_curse_uncurse.go index b6125638143..3f382549996 100644 --- a/deployment/ccip/changeset/cs_rmn_curse_uncurse.go +++ b/deployment/ccip/changeset/cs_rmn_curse_uncurse.go @@ -219,7 +219,8 @@ func RMNCurseChangeset(e deployment.Environment, cfg RMNCurseConfig) (deployment if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(e, state, cfg.MCMS) + + deployerGroup := NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext("proposal to curse RMNs: " + cfg.Reason) // Generate curse actions var curseActions []RMNCurseAction @@ -263,7 +264,7 @@ func RMNCurseChangeset(e deployment.Environment, cfg RMNCurseConfig) (deployment } } - return deployerGroup.Enact("proposal to curse RMNs: " + cfg.Reason) + return deployerGroup.Enact() } // RMNUncurseChangeset creates a new changeset for uncursing chains or lanes on RMNRemote contracts. @@ -289,7 +290,8 @@ func RMNUncurseChangeset(e deployment.Environment, cfg RMNCurseConfig) (deployme if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(e, state, cfg.MCMS) + + deployerGroup := NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext("proposal to uncurse RMNs: " + cfg.Reason) // Generate curse actions var curseActions []RMNCurseAction @@ -335,5 +337,5 @@ func RMNUncurseChangeset(e deployment.Environment, cfg RMNCurseConfig) (deployme } } - return deployerGroup.Enact("proposal to uncurse RMNs: %s" + cfg.Reason) + return deployerGroup.Enact() } diff --git a/deployment/ccip/changeset/cs_set_pool.go b/deployment/ccip/changeset/cs_set_pool.go index 96661d1fe65..8db2f5dedbc 100644 --- a/deployment/ccip/changeset/cs_set_pool.go +++ b/deployment/ccip/changeset/cs_set_pool.go @@ -34,7 +34,8 @@ func SetPoolChangeset(env deployment.Environment, c TokenAdminRegistryChangesetC if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(env, state, c.MCMS) + + deployerGroup := NewDeployerGroup(env, state, c.MCMS).WithDeploymentContext("set pool for tokens on token admin registries") for chainSelector, tokenSymbolToPoolInfo := range c.Pools { chain := env.Chains[chainSelector] @@ -55,5 +56,5 @@ func SetPoolChangeset(env deployment.Environment, c TokenAdminRegistryChangesetC } } - return deployerGroup.Enact("set pool for tokens on token admin registries") + return deployerGroup.Enact() } diff --git a/deployment/ccip/changeset/cs_transfer_admin_role.go b/deployment/ccip/changeset/cs_transfer_admin_role.go index a5d9269dc0c..141a9cdf1ef 100644 --- a/deployment/ccip/changeset/cs_transfer_admin_role.go +++ b/deployment/ccip/changeset/cs_transfer_admin_role.go @@ -39,7 +39,8 @@ func TransferAdminRoleChangeset(env deployment.Environment, c TokenAdminRegistry if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(env, state, c.MCMS) + + deployerGroup := NewDeployerGroup(env, state, c.MCMS).WithDeploymentContext("transfer admin role for tokens on token admin registries") for chainSelector, tokenSymbolToPoolInfo := range c.Pools { chain := env.Chains[chainSelector] @@ -60,5 +61,5 @@ func TransferAdminRoleChangeset(env deployment.Environment, c TokenAdminRegistry } } - return deployerGroup.Enact("transfer admin role for tokens on token admin registries") + return deployerGroup.Enact() } diff --git a/deployment/ccip/changeset/cs_update_rmn_config.go b/deployment/ccip/changeset/cs_update_rmn_config.go index 07c6333ab76..551e7e564b1 100644 --- a/deployment/ccip/changeset/cs_update_rmn_config.go +++ b/deployment/ccip/changeset/cs_update_rmn_config.go @@ -565,7 +565,8 @@ func SetRMNHomeDynamicConfigChangeset(e deployment.Environment, cfg SetRMNHomeDy if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(e, state, cfg.MCMS) + + deployerGroup := NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext("set RMNHome dynamic config") chain, exists := e.Chains[cfg.HomeChainSelector] if !exists { @@ -588,7 +589,7 @@ func SetRMNHomeDynamicConfigChangeset(e deployment.Environment, cfg SetRMNHomeDy return deployment.ChangesetOutput{}, fmt.Errorf("failed to set RMNHome dynamic config for chain %s: %w", chain.String(), err) } - return deployerGroup.Enact("Set RMNHome dynamic config") + return deployerGroup.Enact() } type RevokeCandidateConfig struct { @@ -635,7 +636,8 @@ func RevokeRMNHomeCandidateConfigChangeset(e deployment.Environment, cfg RevokeC if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - deployerGroup := NewDeployerGroup(e, state, cfg.MCMS) + + deployerGroup := NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext("revoke candidate config") chain, exists := e.Chains[cfg.HomeChainSelector] if !exists { @@ -657,7 +659,7 @@ func RevokeRMNHomeCandidateConfigChangeset(e deployment.Environment, cfg RevokeC return deployment.ChangesetOutput{}, fmt.Errorf("failed to revoke candidate config for chain %s: %w", chain.String(), err) } - return deployerGroup.Enact("Revoke candidate config") + return deployerGroup.Enact() } func SetRMNRemoteConfigChangeset(e deployment.Environment, config SetRMNRemoteConfig) (deployment.ChangesetOutput, error) { diff --git a/deployment/ccip/changeset/deployer_group.go b/deployment/ccip/changeset/deployer_group.go index a552d6d9f9b..6ebf5ce9658 100644 --- a/deployment/ccip/changeset/deployer_group.go +++ b/deployment/ccip/changeset/deployer_group.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "slices" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -23,10 +24,51 @@ type MCMSConfig struct { } type DeployerGroup struct { - e deployment.Environment - state CCIPOnChainState - mcmConfig *MCMSConfig - transactions map[uint64][]*types.Transaction + e deployment.Environment + state CCIPOnChainState + mcmConfig *MCMSConfig + deploymentContext *DeploymentContext +} + +type DeploymentContext struct { + description string + transactions map[uint64][]*types.Transaction + previousConfig *DeploymentContext +} + +func NewDeploymentContext(description string) *DeploymentContext { + return &DeploymentContext{ + description: description, + transactions: make(map[uint64][]*types.Transaction), + previousConfig: nil, + } +} + +func (d *DeploymentContext) Fork(description string) *DeploymentContext { + return &DeploymentContext{ + description: description, + transactions: make(map[uint64][]*types.Transaction), + previousConfig: d, + } +} + +type DeployerGroupWithContext interface { + WithDeploymentContext(description string) *DeployerGroup +} + +type deployerGroupBuilder struct { + e deployment.Environment + state CCIPOnChainState + mcmConfig *MCMSConfig +} + +func (d *deployerGroupBuilder) WithDeploymentContext(description string) *DeployerGroup { + return &DeployerGroup{ + e: d.e, + mcmConfig: d.mcmConfig, + state: d.state, + deploymentContext: NewDeploymentContext(description), + } } // DeployerGroup is an abstraction that lets developers write their changeset @@ -41,12 +83,20 @@ type DeployerGroup struct { // state.Chains[selector].RMNRemote.Curse() // # Execute the transaction or create the proposal // deployerGroup.Enact("Curse RMNRemote") -func NewDeployerGroup(e deployment.Environment, state CCIPOnChainState, mcmConfig *MCMSConfig) *DeployerGroup { +func NewDeployerGroup(e deployment.Environment, state CCIPOnChainState, mcmConfig *MCMSConfig) DeployerGroupWithContext { + return &deployerGroupBuilder{ + e: e, + mcmConfig: mcmConfig, + state: state, + } +} + +func (d *DeployerGroup) WithDeploymentContext(description string) *DeployerGroup { return &DeployerGroup{ - e: e, - mcmConfig: mcmConfig, - state: state, - transactions: make(map[uint64][]*types.Transaction), + e: d.e, + mcmConfig: d.mcmConfig, + state: d.state, + deploymentContext: d.deploymentContext.Fork(description), } } @@ -94,77 +144,145 @@ func (d *DeployerGroup) GetDeployer(chain uint64) (*bind.TransactOpts, error) { startingNonce = new(big.Int).SetUint64(nonce) } + dc := d.deploymentContext sim.Signer = func(a common.Address, t *types.Transaction) (*types.Transaction, error) { - // Update the nonce to consider the transactions that have been sent - sim.Nonce = big.NewInt(0).Add(startingNonce, big.NewInt(int64(len(d.transactions[chain]))+1)) + txCount, err := d.getTransactionCount(chain) + if err != nil { + return nil, err + } + + currentNonce := big.NewInt(0).Add(startingNonce, txCount) tx, err := oldSigner(a, t) if err != nil { return nil, err } - d.transactions[chain] = append(d.transactions[chain], tx) + dc.transactions[chain] = append(dc.transactions[chain], tx) + // Update the nonce to consider the transactions that have been sent + sim.Nonce = big.NewInt(0).Add(currentNonce, big.NewInt(1)) return tx, nil } return sim, nil } -func (d *DeployerGroup) Enact(deploymentDescription string) (deployment.ChangesetOutput, error) { +func (d *DeployerGroup) getContextChainInOrder() []*DeploymentContext { + contexts := make([]*DeploymentContext, 0) + for c := d.deploymentContext; c != nil; c = c.previousConfig { + contexts = append(contexts, c) + } + slices.Reverse(contexts) + return contexts +} + +func (d *DeployerGroup) getTransactions() map[uint64][]*types.Transaction { + transactions := make(map[uint64][]*types.Transaction) + for _, c := range d.getContextChainInOrder() { + for k, v := range c.transactions { + transactions[k] = append(transactions[k], v...) + } + } + return transactions +} + +func (d *DeployerGroup) getTransactionCount(chain uint64) (*big.Int, error) { + txs := d.getTransactions() + return big.NewInt(int64(len(txs[chain]))), nil +} + +func (d *DeployerGroup) Enact() (deployment.ChangesetOutput, error) { if d.mcmConfig != nil { - return d.enactMcms(deploymentDescription) + return d.enactMcms() } return d.enactDeployer() } -func (d *DeployerGroup) enactMcms(deploymentDescription string) (deployment.ChangesetOutput, error) { - batches := make([]timelock.BatchChainOperation, 0) - for selector, txs := range d.transactions { - mcmOps := make([]mcms.Operation, len(txs)) - for i, tx := range txs { - mcmOps[i] = mcms.Operation{ - To: *tx.To(), - Data: tx.Data(), - Value: tx.Value(), +func (d *DeployerGroup) enactMcms() (deployment.ChangesetOutput, error) { + contexts := d.getContextChainInOrder() + proposals := make([]timelock.MCMSWithTimelockProposal, 0) + for _, dc := range contexts { + batches := make([]timelock.BatchChainOperation, 0) + for selector, txs := range dc.transactions { + mcmOps := make([]mcms.Operation, len(txs)) + for i, tx := range txs { + mcmOps[i] = mcms.Operation{ + To: *tx.To(), + Data: tx.Data(), + Value: tx.Value(), + } } + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(selector), + Batch: mcmOps, + }) + } + + if len(batches) == 0 { + d.e.Logger.Warnf("No batch was produced from deployment context skipping proposal: %s", dc.description) + continue } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(selector), - Batch: mcmOps, - }) - } - 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, - proposerMCMSes, - batches, - deploymentDescription, - d.mcmConfig.MinDelay, - ) + prop, err := proposalutils.BuildProposalFromBatches( + timelocksPerChain, + proposerMCMSes, + batches, + dc.description, + d.mcmConfig.MinDelay, + ) - if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal %w", err) + // Update the proposal metadata to incorporate the startingOpCount + // from the previous proposal + if len(proposals) > 0 { + previousProposal := proposals[len(proposals)-1] + for chain, metadata := range previousProposal.ChainMetadata { + nextStartingOp := metadata.StartingOpCount + getBatchCountForChain(chain, prop) + prop.ChainMetadata[chain] = mcms.ChainMetadata{ + StartingOpCount: nextStartingOp, + MCMAddress: prop.ChainMetadata[chain].MCMAddress, + } + } + } + + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal %w", err) + } + + proposals = append(proposals, *prop) } return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*prop}, + Proposals: proposals, }, nil } +func getBatchCountForChain(chain mcms.ChainIdentifier, m *timelock.MCMSWithTimelockProposal) uint64 { + batches := make([]timelock.BatchChainOperation, 0) + for _, t := range m.Transactions { + if t.ChainIdentifier == chain { + batches = append(batches, t) + } + } + return uint64(len(batches)) +} + func (d *DeployerGroup) enactDeployer() (deployment.ChangesetOutput, error) { - for selector, txs := range d.transactions { - for _, tx := range txs { - err := d.e.Chains[selector].Client.SendTransaction(context.Background(), tx) - if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("failed to send transaction: %w", err) - } + contexts := d.getContextChainInOrder() + for _, c := range contexts { + for selector, txs := range c.transactions { + for _, tx := range txs { + err := d.e.Chains[selector].Client.SendTransaction(context.Background(), tx) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to send transaction: %w", err) + } - _, err = d.e.Chains[selector].Confirm(tx) - if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("waiting for tx to be mined failed: %w", err) + _, err = d.e.Chains[selector].Confirm(tx) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("waiting for tx to be mined failed: %w", err) + } } } } diff --git a/deployment/ccip/changeset/deployer_group_test.go b/deployment/ccip/changeset/deployer_group_test.go index ba598ec74e8..0f670f0d2f6 100644 --- a/deployment/ccip/changeset/deployer_group_test.go +++ b/deployment/ccip/changeset/deployer_group_test.go @@ -1,18 +1,33 @@ package changeset_test import ( + "fmt" "math/big" "testing" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" + "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" ) +type mintConfig struct { + selectorIndex uint64 + amount *big.Int +} + +type dummyMultiChainDeployerGroupChangesetConfig struct { + address common.Address + mints []mintConfig + MCMS *changeset.MCMSConfig +} + type dummyDeployerGroupChangesetConfig struct { selector uint64 address common.Address @@ -20,6 +35,20 @@ type dummyDeployerGroupChangesetConfig struct { MCMS *changeset.MCMSConfig } +type dummyEmptyBatchChangesetConfig struct { + MCMS *changeset.MCMSConfig +} + +func dummyEmptyBatchChangeset(e deployment.Environment, cfg dummyEmptyBatchChangesetConfig) (deployment.ChangesetOutput, error) { + state, err := changeset.LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + + group := changeset.NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext("empty batch") + return group.Enact() +} + func dummyDeployerGroupGrantMintChangeset(e deployment.Environment, cfg dummyDeployerGroupChangesetConfig) (deployment.ChangesetOutput, error) { state, err := changeset.LoadOnchainState(e) if err != nil { @@ -28,7 +57,7 @@ func dummyDeployerGroupGrantMintChangeset(e deployment.Environment, cfg dummyDep token := state.Chains[cfg.selector].LinkToken - group := changeset.NewDeployerGroup(e, state, cfg.MCMS) + group := changeset.NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext("grant mint role") deployer, err := group.GetDeployer(cfg.selector) if err != nil { return deployment.ChangesetOutput{}, err @@ -39,7 +68,7 @@ func dummyDeployerGroupGrantMintChangeset(e deployment.Environment, cfg dummyDep return deployment.ChangesetOutput{}, err } - return group.Enact("Grant mint role") + return group.Enact() } func dummyDeployerGroupMintChangeset(e deployment.Environment, cfg dummyDeployerGroupChangesetConfig) (deployment.ChangesetOutput, error) { @@ -50,7 +79,7 @@ func dummyDeployerGroupMintChangeset(e deployment.Environment, cfg dummyDeployer token := state.Chains[cfg.selector].LinkToken - group := changeset.NewDeployerGroup(e, state, cfg.MCMS) + group := changeset.NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext("mint tokens") deployer, err := group.GetDeployer(cfg.selector) if err != nil { return deployment.ChangesetOutput{}, err @@ -63,7 +92,64 @@ func dummyDeployerGroupMintChangeset(e deployment.Environment, cfg dummyDeployer } } - return group.Enact("Mint tokens") + return group.Enact() +} + +func dummyDeployerGroupGrantMintMultiChainChangeset(e deployment.Environment, cfg dummyMultiChainDeployerGroupChangesetConfig) (deployment.ChangesetOutput, error) { + state, err := changeset.LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + + group := changeset.NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext("grant mint role") + for _, mint := range cfg.mints { + selector := e.AllChainSelectors()[mint.selectorIndex] + token := state.Chains[selector].LinkToken + + deployer, err := group.GetDeployer(selector) + if err != nil { + return deployment.ChangesetOutput{}, err + } + + _, err = token.GrantMintRole(deployer, deployer.From) + if err != nil { + return deployment.ChangesetOutput{}, err + } + } + + return group.Enact() +} + +func dummyDeployerGroupMintMultiDeploymentContextChangeset(e deployment.Environment, cfg dummyMultiChainDeployerGroupChangesetConfig) (deployment.ChangesetOutput, error) { + state, err := changeset.LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + + var group *changeset.DeployerGroup + var deployer *bind.TransactOpts + + for i, mint := range cfg.mints { + selector := e.AllChainSelectors()[mint.selectorIndex] + token := state.Chains[selector].LinkToken + + if group == nil { + group = changeset.NewDeployerGroup(e, state, cfg.MCMS).WithDeploymentContext(fmt.Sprintf("mint tokens %d", i+1)) + } else { + group = group.WithDeploymentContext(fmt.Sprintf("mint tokens %d", i+1)) + } + deployer, err = group.GetDeployer(selector) + if err != nil { + return deployment.ChangesetOutput{}, err + } + + _, err = token.Mint(deployer, cfg.address, mint.amount) + if err != nil { + return deployment.ChangesetOutput{}, err + } + } + + return group.Enact() } type deployerGroupTestCase struct { @@ -191,3 +277,152 @@ func TestDeployerGroupMCMS(t *testing.T) { }) } } + +func TestDeployerGroupGenerateMultipleProposals(t *testing.T) { + tc := dummyMultiChainDeployerGroupChangesetConfig{ + address: common.HexToAddress("0x455E5AA18469bC6ccEF49594645666C587A3a71B"), + mints: []mintConfig{ + { + selectorIndex: 0, + amount: big.NewInt(1), + }, + { + selectorIndex: 0, + amount: big.NewInt(2), + }, + { + selectorIndex: 1, + amount: big.NewInt(4), + }, + }, + MCMS: &changeset.MCMSConfig{ + MinDelay: 0, + }, + } + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(2)) + state, err := changeset.LoadOnchainState(e.Env) + require.NoError(t, err) + + timelocksPerChain := changeset.BuildTimelockPerChain(e.Env, state) + + contractsByChain := make(map[uint64][]common.Address) + for _, chain := range e.Env.AllChainSelectors() { + contractsByChain[chain] = []common.Address{state.Chains[chain].LinkToken.Address()} + } + + _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock), + Config: commonchangeset.TransferToMCMSWithTimelockConfig{ + ContractsByChain: contractsByChain, + MinDelay: 0, + }, + }, + }) + require.NoError(t, err) + + _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(dummyDeployerGroupGrantMintMultiChainChangeset), + Config: tc, + }, + }) + require.NoError(t, err) + + cs, err := dummyDeployerGroupMintMultiDeploymentContextChangeset(e.Env, tc) + require.NoError(t, err) + require.Len(t, cs.Proposals, len(tc.mints)) + require.Equal(t, "mint tokens 1", cs.Proposals[0].Description) + require.Equal(t, "mint tokens 2", cs.Proposals[1].Description) + require.Equal(t, "mint tokens 3", cs.Proposals[2].Description) + require.Equal(t, uint64(2), cs.Proposals[0].ChainMetadata[mcms.ChainIdentifier(e.Env.AllChainSelectors()[tc.mints[0].selectorIndex])].StartingOpCount) + require.Equal(t, uint64(3), cs.Proposals[1].ChainMetadata[mcms.ChainIdentifier(e.Env.AllChainSelectors()[tc.mints[1].selectorIndex])].StartingOpCount) + require.Equal(t, uint64(2), cs.Proposals[2].ChainMetadata[mcms.ChainIdentifier(e.Env.AllChainSelectors()[tc.mints[2].selectorIndex])].StartingOpCount) +} + +func TestDeployerGroupMultipleProposalsMCMS(t *testing.T) { + cfg := dummyMultiChainDeployerGroupChangesetConfig{ + address: common.HexToAddress("0x455E5AA18469bC6ccEF49594645666C587A3a71B"), + mints: []mintConfig{ + { + selectorIndex: 0, + amount: big.NewInt(1), + }, + { + selectorIndex: 0, + amount: big.NewInt(2), + }, + }, + MCMS: &changeset.MCMSConfig{ + MinDelay: 0, + }, + } + + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(2)) + + state, err := changeset.LoadOnchainState(e.Env) + require.NoError(t, err) + + timelocksPerChain := changeset.BuildTimelockPerChain(e.Env, state) + + contractsByChain := make(map[uint64][]common.Address) + for _, chain := range e.Env.AllChainSelectors() { + contractsByChain[chain] = []common.Address{state.Chains[chain].LinkToken.Address()} + } + + _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock), + Config: commonchangeset.TransferToMCMSWithTimelockConfig{ + ContractsByChain: contractsByChain, + MinDelay: 0, + }, + }, + }) + require.NoError(t, err) + + _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(dummyDeployerGroupGrantMintMultiChainChangeset), + Config: cfg, + }, + }) + require.NoError(t, err) + + _, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(dummyDeployerGroupMintMultiDeploymentContextChangeset), + Config: cfg, + }, + }) + require.NoError(t, err) + + state, err = changeset.LoadOnchainState(e.Env) + require.NoError(t, err) + + token := state.Chains[e.HomeChainSel].LinkToken + + amount, err := token.BalanceOf(nil, cfg.address) + require.NoError(t, err) + + sumOfMints := big.NewInt(0) + for _, mint := range cfg.mints { + sumOfMints = sumOfMints.Add(sumOfMints, mint.amount) + } + + require.Equal(t, sumOfMints, amount) +} + +func TestEmptyBatch(t *testing.T) { + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithNumOfChains(2)) + + cfg := dummyEmptyBatchChangesetConfig{ + MCMS: &changeset.MCMSConfig{ + MinDelay: 0, + }, + } + + result, err := dummyEmptyBatchChangeset(e.Env, cfg) + require.NoError(t, err) + require.Empty(t, result.Proposals) +} From 380d8fa30b452cc494d88495639185650f687a3d Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Fri, 31 Jan 2025 11:22:48 -0600 Subject: [PATCH 26/43] core/chains/evm: remove heavyweight db package dependency (#16157) --- .../evm/forwarders/forwarder_manager_test.go | 17 +- core/chains/evm/logpoller/log_poller_test.go | 14 +- core/chains/evm/logpoller/orm_test.go | 9 +- core/chains/evm/txmgr/broadcaster_test.go | 179 +++++++++--------- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../ocr2/testhelpers/onchain_config.go | 25 +-- core/store/store.go | 8 + core/utils/testutils/heavyweight/orm.go | 54 ++---- deployment/go.mod | 2 +- deployment/go.sum | 4 +- evm/README.md | 2 +- evm/client/clienttest/clienttest.go | 1 - evm/testutils/sql.go | 33 ++++ go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 +- internal/testdb/testdb.go | 65 +------ main_test.go | 76 ++++---- 22 files changed, 224 insertions(+), 289 deletions(-) create mode 100644 core/store/store.go diff --git a/core/chains/evm/forwarders/forwarder_manager_test.go b/core/chains/evm/forwarders/forwarder_manager_test.go index d54367c303c..2eeefc5dc23 100644 --- a/core/chains/evm/forwarders/forwarder_manager_test.go +++ b/core/chains/evm/forwarders/forwarder_manager_test.go @@ -10,11 +10,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient/simulated" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/libocr/gethwrappers2/testocr2aggregator" + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" @@ -25,10 +25,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/evm/client" + "github.com/smartcontractkit/chainlink/v2/evm/config/configtest" "github.com/smartcontractkit/chainlink/v2/evm/testutils" ubig "github.com/smartcontractkit/chainlink/v2/evm/utils/big" ) @@ -36,8 +34,7 @@ import ( func TestFwdMgr_MaybeForwardTransaction(t *testing.T) { lggr := logger.Test(t) db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) owner := testutils.MustNewSimTransactor(t) ctx := testutils.Context(t) @@ -106,8 +103,7 @@ func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) { lggr := logger.Test(t) db := testutils.NewSqlxDB(t) ctx := testutils.Context(t) - cfg := configtest.NewTestGeneralConfig(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) owner := testutils.MustNewSimTransactor(t) b := simulated.NewBackend(types.GenesisAlloc{ owner.From: { @@ -156,8 +152,7 @@ func TestFwdMgr_InvalidForwarderForOCR2FeedsStates(t *testing.T) { lggr := logger.Test(t) db := testutils.NewSqlxDB(t) ctx := testutils.Context(t) - cfg := configtest.NewTestGeneralConfig(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) owner := testutils.MustNewSimTransactor(t) ec := simulated.NewBackend(types.GenesisAlloc{ owner.From: { @@ -229,7 +224,7 @@ func TestFwdMgr_InvalidForwarderForOCR2FeedsStates(t *testing.T) { require.ErrorIs(t, err, forwarders.ErrForwarderForEOANotFound) require.True(t, utils.IsZero(addr)) - onchainConfig, err := testhelpers.GenerateDefaultOCR2OnchainConfig(big.NewInt(0), big.NewInt(10)) + onchainConfig, err := median.StandardOnchainConfigCodec{}.Encode(ctx, median.OnchainConfig{Min: big.NewInt(0), Max: big.NewInt(10)}) require.NoError(t, err) _, err = ocr2.SetConfig(owner, diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index bb376913627..fe475135796 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -22,9 +22,8 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink-common/pkg/logger" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/query" "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" @@ -33,9 +32,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/log_emitter" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" "github.com/smartcontractkit/chainlink/v2/evm/client" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" "github.com/smartcontractkit/chainlink/v2/evm/config/chaintype" "github.com/smartcontractkit/chainlink/v2/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink/v2/evm/types" @@ -89,7 +87,7 @@ func populateDatabase(t testing.TB, o logpoller.ORM, chainID *big.Int) (common.H func BenchmarkSelectLogsCreatedAfter(b *testing.B) { chainId := big.NewInt(137) ctx := testutils.Context(b) - _, db := heavyweight.FullTestDBV2(b, nil) + db := testutils.NewIndependentSqlxDB(b) o := logpoller.NewORM(chainId, db, logger.Test(b)) event, address, _ := populateDatabase(b, o, chainId) @@ -107,7 +105,7 @@ func BenchmarkSelectLogsCreatedAfter(b *testing.B) { func TestPopulateLoadedDB(t *testing.T) { t.Skip("Only for local load testing and query analysis") - _, db := heavyweight.FullTestDBV2(t, nil) + db := testutils.NewIndependentSqlxDB(t) ctx := testutils.Context(t) chainID := big.NewInt(137) @@ -1532,7 +1530,7 @@ func TestTooManyLogResults(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - ec := evmtest.NewEthClientMockWithDefaultChain(t) + ec := clienttest.NewClientWithDefaultChainID(t) lggr, obs := logger.TestObserved(t, zapcore.DebugLevel) chainID := testutils.NewRandomEVMChainID() db := testutils.NewSqlxDB(t) @@ -1960,7 +1958,7 @@ func Test_PruneOldBlocks(t *testing.T) { func TestFindLCA(t *testing.T) { ctx := testutils.Context(t) - ec := evmtest.NewEthClientMockWithDefaultChain(t) + ec := clienttest.NewClientWithDefaultChainID(t) lggr := logger.Test(t) chainID := testutils.NewRandomEVMChainID() db := testutils.NewSqlxDB(t) diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 4b4a22d8001..2775e1d3478 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -23,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" "github.com/smartcontractkit/chainlink/v2/evm/testutils" "github.com/smartcontractkit/chainlink/v2/evm/types" "github.com/smartcontractkit/chainlink/v2/evm/utils" @@ -2046,7 +2045,7 @@ func TestInsertLogsWithBlock(t *testing.T) { // We need full db here, because we want to test transaction rollbacks. // Using testutils.NewSqlxDB(t) will run all tests in TXs which is not desired for this type of test // (inner tx rollback will rollback outer tx, blocking rest of execution) - _, db := heavyweight.FullTestDBV2(t, nil) + db := testutils.NewIndependentSqlxDB(t) o := logpoller.NewORM(chainID, db, logger.Test(t)) correctLog := GenLog(chainID, 1, 1, utils.RandomAddress().String(), event[:], address) @@ -2133,7 +2132,7 @@ func TestInsertLogsInTx(t *testing.T) { ctx := testutils.Context(t) // We need full db here, because we want to test transaction rollbacks. - _, db := heavyweight.FullTestDBV2(t, nil) + db := testutils.NewIndependentSqlxDB(t) o := logpoller.NewORM(chainID, db, logger.Test(t)) logs := make([]logpoller.Log, maxLogsSize, maxLogsSize+1) @@ -2280,7 +2279,7 @@ func TestSelectLogsDataWordBetween(t *testing.T) { func Benchmark_LogsDataWordBetween(b *testing.B) { chainId := big.NewInt(137) - _, db := heavyweight.FullTestDBV2(b, nil) + db := testutils.NewIndependentSqlxDB(b) o := logpoller.NewORM(chainId, db, logger.Test(b)) ctx := testutils.Context(b) @@ -2333,7 +2332,7 @@ func Benchmark_LogsDataWordBetween(b *testing.B) { func Benchmark_DeleteExpiredLogs(b *testing.B) { chainId := big.NewInt(137) - _, db := heavyweight.FullTestDBV2(b, nil) + db := testutils.NewIndependentSqlxDB(b) o := logpoller.NewORM(chainId, db, logger.Test(b)) ctx := testutils.Context(b) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 6319dfb00dc..ad7342c9707 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -35,15 +35,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" "github.com/smartcontractkit/chainlink/v2/evm/assets" "github.com/smartcontractkit/chainlink/v2/evm/client" "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" evmconfig "github.com/smartcontractkit/chainlink/v2/evm/config" "github.com/smartcontractkit/chainlink/v2/evm/config/chaintype" + "github.com/smartcontractkit/chainlink/v2/evm/config/configtest" + "github.com/smartcontractkit/chainlink/v2/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/evm/keystore" @@ -52,13 +50,21 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/evm/types" ) +var dbListenerCfg txmgr.ListenerConfig = testListenerConfig{} + +type testListenerConfig struct{} + +func (l testListenerConfig) FallbackPollInterval() time.Duration { + return 1 * time.Minute +} + // NewEthBroadcaster creates a new txmgr.EthBroadcaster for use in testing. func NewTestEthBroadcaster( t testing.TB, txStore txmgr.TestEvmTxStore, ethClient client.Client, keyStore keystore.Eth, - gconfig chainlink.GeneralConfig, + databaseListener txmgr.ListenerConfig, config evmconfig.ChainScopedConfig, checkerFactory txmgr.TransmitCheckerFactory, nonceAutoSync bool, @@ -73,7 +79,13 @@ func NewTestEthBroadcaster( return gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), nil, ge.BlockHistory(), lggr, nil) }, ge.EIP1559DynamicFees(), ge, ethClient) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) - ethBroadcaster := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), gconfig.Database().Listener(), keyStore, txBuilder, nonceTracker, lggr, checkerFactory, nonceAutoSync, "") + ethBroadcaster := txmgrcommon.NewBroadcaster(txStore, + txmgr.NewEvmTxmClient(ethClient, nil), + txmgr.NewEvmTxmConfig(config.EVM()), + txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), + config.EVM().Transactions(), + databaseListener, keyStore, txBuilder, nonceTracker, + lggr, checkerFactory, nonceAutoSync, "") // Mark instance as test ethBroadcaster.XXXTestDisableUnstartedTxAutoProcessing() @@ -82,9 +94,9 @@ func NewTestEthBroadcaster( } func TestEthBroadcaster_Lifecycle(t *testing.T) { - cfg, db := heavyweight.FullTestDBV2(t, nil) + db := testutils.NewIndependentSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) ethKeyStore := cltest.NewKeyStore(t, db).Eth() cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -98,7 +110,7 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), - cfg.Database().Listener(), + dbListenerCfg, ethKeyStore, txBuilder, logger.Test(t), @@ -141,9 +153,8 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { // Failure to load next sequnce map should not fail Broadcaster startup func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) { db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) ethKeyStore := cltest.NewKeyStore(t, db).Eth() cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -157,7 +168,7 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), - cfg.Database().Listener(), + dbListenerCfg, ethKeyStore, txBuilder, logger.Test(t), @@ -174,7 +185,6 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) ctx := tests.Context(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() @@ -182,14 +192,14 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := clienttest.NewClientWithDefaultChainID(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) checkerFactory := &txmgr.CheckerFactory{Client: ethClient} ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() ethClient.On("NonceAt", mock.Anything, otherAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, checkerFactory, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, checkerFactory, false, nonceTracker) toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") timeNow := time.Now() @@ -380,16 +390,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }) rnd := int64(1000000000 + rand.Intn(5000)) - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) - c.EVM[0].GasEstimator.TipCapDefault = assets.NewWeiI(rnd) - c.EVM[0].GasEstimator.FeeCapDefault = assets.NewWeiI(rnd + 1) - c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(rnd + 2) + evmcfg = configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.EIP1559DynamicFees = ptr(true) + c.GasEstimator.TipCapDefault = assets.NewWeiI(rnd) + c.GasEstimator.FeeCapDefault = assets.NewWeiI(rnd + 1) + c.GasEstimator.PriceMax = assets.NewWeiI(rnd + 2) }) - evmcfg = evmtest.NewChainScopedConfig(t, cfg) ethClient.On("NonceAt", mock.Anything, otherAddress, mock.Anything).Return(uint64(1), nil).Once() nonceTracker = txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, checkerFactory, false, nonceTracker) + eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, checkerFactory, false, nonceTracker) t.Run("sends transactions with type 0x2 in EIP-1559 mode", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -547,18 +556,17 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { func TestEthBroadcaster_TransmitChecking(t *testing.T) { db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) ctx := tests.Context(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := clienttest.NewClientWithDefaultChainID(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) checkerFactory := &testCheckerFactory{} ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, checkerFactory, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, checkerFactory, false, nonceTracker) checker := txmgr.TransmitCheckerSpec{ CheckerType: txmgr.TransmitCheckerTypeSimulate, @@ -631,9 +639,9 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testing.T) { // non-transactional DB needed because we deliberately test for FK violation - cfg, db := heavyweight.FullTestDBV2(t, nil) + db := testutils.NewIndependentSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ccfg := evmtest.NewChainScopedConfig(t, cfg) + ccfg := configtest.NewChainScopedConfig(t, nil) evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ethClient := clienttest.NewClientWithDefaultChainID(t) ethKeyStore := cltest.NewKeyStore(t, db).Eth() @@ -656,7 +664,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi evmcfg, txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), - cfg.Database().Listener(), + dbListenerCfg, ethKeyStore, txBuilder, logger.Test(t), @@ -693,22 +701,21 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing.T) { db := testutils.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - // Configured gas price changed - lm := decimal.RequireFromString("1.3") - c.EVM[0].GasEstimator.LimitMultiplier = &lm - }) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + // Configured gas price changed + lm := decimal.RequireFromString("1.3") + c.GasEstimator.LimitMultiplier = &lm + }) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { assert.Equal(t, int(1600), int(tx.Gas())) @@ -741,8 +748,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { nextNonce := evmtypes.Nonce(916714082576372851) firstNonce := nextNonce secondNonce := nextNonce + 1 - cfg := configtest.NewGeneralConfig(t, nil) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) ctx := tests.Context(t) t.Run("cannot be more than one transaction per address in an unfinished state", func(t *testing.T) { @@ -790,7 +796,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so evm.key_states.next_nonce has not been @@ -829,7 +835,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -866,7 +872,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -902,7 +908,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -940,7 +946,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -973,16 +979,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { // Configured gas price changed - c.EVM[0].GasEstimator.PriceDefault = assets.NewWeiI(500000000000) + c.GasEstimator.PriceDefault = assets.NewWeiI(500000000000) }) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -1036,19 +1041,18 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { encodedPayload := []byte{0, 1} db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) txmClient := txmgr.NewEvmTxmClient(ethClient, nil) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmClient) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) ctx := tests.Context(t) require.NoError(t, commonutils.JustError(db.Exec(`SET CONSTRAINTS fk_pipeline_runs_pruning_key DEFERRED`))) @@ -1182,7 +1186,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator(), ethClient) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) - eb2 := txmgr.NewEvmBroadcaster(txStore, txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, lggr, &testCheckerFactory{}, false, "") + eb2 := txmgr.NewEvmBroadcaster(txStore, txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), dbListenerCfg, ethKeyStore, txBuilder, lggr, &testCheckerFactory{}, false, "") retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1502,11 +1506,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // In this scenario the node operator REALLY fucked up and set the bump // to zero (even though that should not be possible due to config // validation) - evmcfg2 := evmtest.NewChainScopedConfig(t, configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) - c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) - })) - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + evmcfg2 := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.BumpMin = assets.NewWeiI(0) + c.GasEstimator.BumpPercent = ptr[uint16](0) + }) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID) // First was underpriced @@ -1591,14 +1595,14 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // In this scenario the node operator REALLY fucked up and set the bump // to zero (even though that should not be possible due to config // validation) - evmcfg2 := evmtest.NewChainScopedConfig(t, configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) - c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) - c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) - })) + evmcfg2 := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.EIP1559DynamicFees = ptr(true) + c.GasEstimator.BumpMin = assets.NewWeiI(0) + c.GasEstimator.BumpPercent = ptr[uint16](0) + }) localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID) underpricedError := "transaction underpriced" localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) @@ -1624,13 +1628,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { gasTipCapDefault := assets.NewWeiI(42) - evmcfg2 := evmtest.NewChainScopedConfig(t, configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) - c.EVM[0].GasEstimator.TipCapDefault = gasTipCapDefault - })) + evmcfg2 := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.EIP1559DynamicFees = ptr(true) + c.GasEstimator.TipCapDefault = gasTipCapDefault + }) localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) // Second was underpriced but above minimum ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1661,16 +1665,16 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_GasEstimationError(t *testing.T) encodedPayload := []byte{0, 1} db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - cfg.EVMConfigs()[0].GasEstimator.EstimateLimit = ptr(true) // Enabled gas limit estimation - limitMultiplier := float32(1.25) - cfg.EVMConfigs()[0].GasEstimator.LimitMultiplier = ptr(decimal.NewFromFloat32(limitMultiplier)) // Set LimitMultiplier for the buffer txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - config := evmtest.NewChainScopedConfig(t, cfg) + const limitMultiplier = float32(1.25) + config := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.EstimateLimit = ptr(true) // Enabled gas limit estimation + c.GasEstimator.LimitMultiplier = ptr(decimal.NewFromFloat32(limitMultiplier)) // Set LimitMultiplier for the buffer + }) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) @@ -1681,7 +1685,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_GasEstimationError(t *testing.T) return gas.NewFixedPriceEstimator(ge, nil, ge.BlockHistory(), lggr, nil) }, ge.EIP1559DynamicFees(), ge, ethClient) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, estimator) - eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, nonceTracker, lggr, &testCheckerFactory{}, false, "") + eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), dbListenerCfg, ethKeyStore, txBuilder, nonceTracker, lggr, &testCheckerFactory{}, false, "") // Mark instance as test eb.XXXTestDisableUnstartedTxAutoProcessing() @@ -1729,13 +1733,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { localNonce := 0 db := testutils.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) realKeystore := cltest.NewKeyStore(t, db) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, realKeystore.Eth()) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) kst := ksmocks.NewEth(t) @@ -1744,7 +1747,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) ctx := tests.Context(t) _, err := nonceTracker.GetNextSequence(ctx, fromAddress) require.NoError(t, err) @@ -1786,14 +1789,13 @@ func TestEthBroadcaster_Trigger(t *testing.T) { // Simple sanity check to make sure it doesn't block db := testutils.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db).Eth() ethClient := clienttest.NewClientWithDefaultChainID(t) lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) eb.Trigger(testutils.NewAddress()) eb.Trigger(testutils.NewAddress()) @@ -1805,10 +1807,9 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ctx := tests.Context(t) lggr, observed := logger.TestObserved(t, zapcore.DebugLevel) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].NonceAutoSync = ptr(true) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.NonceAutoSync = ptr(true) }) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) evmTxmCfg := txmgr.NewEvmTxmConfig(evmcfg.EVM()) txStore := cltest.NewTestTxStore(t, db) @@ -1831,7 +1832,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { kst.On("EnabledAddressesForChain", mock.Anything, testutils.FixtureChainID).Return(addresses, nil).Once() ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() txmClient := txmgr.NewEvmTxmClient(ethClient, nil) - eb := txmgr.NewEvmBroadcaster(txStore, txmClient, evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, lggr, checkerFactory, false, "") + eb := txmgr.NewEvmBroadcaster(txStore, txmClient, evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), dbListenerCfg, kst, txBuilder, lggr, checkerFactory, false, "") err := eb.Start(ctx) assert.NoError(t, err) @@ -1845,13 +1846,12 @@ func TestEthBroadcaster_NonceTracker_InProgressTx(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := clienttest.NewClientWithDefaultChainID(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) checkerFactory := &txmgr.CheckerFactory{Client: ethClient} lggr := logger.Test(t) ctx := tests.Context(t) @@ -1865,7 +1865,7 @@ func TestEthBroadcaster_NonceTracker_InProgressTx(t *testing.T) { // Tx with nonce 0 in DB will set local nonce map to value to 1 mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(inProgressTxNonce), fromAddress) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg, checkerFactory, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, checkerFactory, false, nonceTracker) // Check the local nonce map was set to 1 higher than in-progress tx nonce nonce := getLocalNextNonce(t, nonceTracker, fromAddress) @@ -1884,10 +1884,9 @@ func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) lggr, observed := logger.TestObserved(t, zapcore.DebugLevel) ge := evmcfg.EVM().GasEstimator() @@ -1908,7 +1907,7 @@ func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) { mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(localNonce), fromAddress) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera)) + eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), dbListenerCfg, ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera)) // Mark instance as test eb.XXXTestDisableUnstartedTxAutoProcessing() servicetest.Run(t, eb) @@ -1929,7 +1928,7 @@ func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) { mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(localNonce), fromAddress) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera)) + eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), dbListenerCfg, ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera)) // Mark instance as test eb.XXXTestDisableUnstartedTxAutoProcessing() servicetest.Run(t, eb) @@ -1950,7 +1949,7 @@ func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) { etx := mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(localNonce), fromAddress) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera)) + eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), dbListenerCfg, ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera)) // Mark instance as test eb.XXXTestDisableUnstartedTxAutoProcessing() servicetest.Run(t, eb) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 9918da212a5..3ce567869e7 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -34,7 +34,7 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/libocr v0.0.0-20241223215956-e5b78d8e3919 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index fa92de23163..9a0feaf87f6 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1333,8 +1333,8 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/core/services/ocr2/testhelpers/onchain_config.go b/core/services/ocr2/testhelpers/onchain_config.go index a2cb6f91f29..9758238b27e 100644 --- a/core/services/ocr2/testhelpers/onchain_config.go +++ b/core/services/ocr2/testhelpers/onchain_config.go @@ -1,31 +1,12 @@ package testhelpers import ( + "context" "math/big" - "github.com/smartcontractkit/libocr/bigbigendian" + "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" ) func GenerateDefaultOCR2OnchainConfig(minValue *big.Int, maxValue *big.Int) ([]byte, error) { - serializedConfig := make([]byte, 0) - - s1, err := bigbigendian.SerializeSigned(1, big.NewInt(1)) // version - if err != nil { - return nil, err - } - serializedConfig = append(serializedConfig, s1...) - - s2, err := bigbigendian.SerializeSigned(24, minValue) // min - if err != nil { - return nil, err - } - serializedConfig = append(serializedConfig, s2...) - - s3, err := bigbigendian.SerializeSigned(24, maxValue) // max - if err != nil { - return nil, err - } - serializedConfig = append(serializedConfig, s3...) - - return serializedConfig, nil + return median.StandardOnchainConfigCodec{}.Encode(context.Background(), median.OnchainConfig{Min: minValue, Max: maxValue}) } diff --git a/core/store/store.go b/core/store/store.go new file mode 100644 index 00000000000..76c74abc23b --- /dev/null +++ b/core/store/store.go @@ -0,0 +1,8 @@ +package store + +import _ "embed" + +//go:embed fixtures/fixtures.sql +var fixturesSQL string + +func FixturesSQL() string { return fixturesSQL } diff --git a/core/utils/testutils/heavyweight/orm.go b/core/utils/testutils/heavyweight/orm.go index 970ec1c89d6..e8266ccf16b 100644 --- a/core/utils/testutils/heavyweight/orm.go +++ b/core/utils/testutils/heavyweight/orm.go @@ -4,8 +4,6 @@ package heavyweight import ( "os" - "path" - "runtime" "strings" "testing" @@ -14,10 +12,11 @@ import ( "github.com/jmoiron/sqlx" + commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" pgcommon "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/pg" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/v2/core/store" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -28,32 +27,27 @@ import ( // FullTestDBV2 creates a pristine DB which runs in a separate database than the normal // unit tests, so you can do things like use other Postgres connection types with it. func FullTestDBV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return KindFixtures.PrepareDB(t, overrideFn) + cfg, db := FullTestDBNoFixturesV2(t, overrideFn) + _, err := db.Exec(store.FixturesSQL()) + require.NoError(t, err) + return cfg, db } // FullTestDBNoFixturesV2 is the same as FullTestDB, but it does not load fixtures. func FullTestDBNoFixturesV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return KindTemplate.PrepareDB(t, overrideFn) + return prepareDB(t, true, overrideFn) } // FullTestDBEmptyV2 creates an empty DB (without migrations). func FullTestDBEmptyV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return KindEmpty.PrepareDB(t, overrideFn) + return prepareDB(t, false, overrideFn) } func generateName() string { - return strings.ReplaceAll(uuid.New().String(), "-", "") + return strings.ReplaceAll(uuid.NewString(), "-", "") } -type Kind int - -const ( - KindEmpty Kind = iota - KindTemplate - KindFixtures -) - -func (c Kind) PrepareDB(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { +func prepareDB(t testing.TB, withTemplate bool, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { tests.SkipShort(t, "FullTestDB") gcfg := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -64,35 +58,21 @@ func (c Kind) PrepareDB(t testing.TB, overrideFn func(c *chainlink.Config, s *ch }) require.NoError(t, os.MkdirAll(gcfg.RootDir(), 0700)) - migrationTestDBURL, err := testdb.CreateOrReplace(gcfg.Database().URL(), generateName(), c != KindEmpty) - require.NoError(t, err) - db, err := pg.NewConnection(tests.Context(t), migrationTestDBURL, pgcommon.DriverPostgres, gcfg.Database()) + t.Cleanup(func() { os.RemoveAll(gcfg.RootDir()) }) + + migrationTestDBURL := testdb.CreateOrReplace(t, gcfg.Database().URL(), generateName(), withTemplate) + db, err := pg.NewConnection(tests.Context(t), migrationTestDBURL.String(), pgcommon.DriverPostgres, gcfg.Database()) require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, db.Close()) // must close before dropping - require.NoError(t, testdb.Drop(*testutils.MustParseURL(t, migrationTestDBURL))) - os.RemoveAll(gcfg.RootDir()) - }) + t.Cleanup(func() { require.NoError(t, db.Close()) }) // must close before dropping + // reset with new URL gcfg = configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.DriverName = pgcommon.DriverPostgres - s.Database.URL = models.MustSecretURL(migrationTestDBURL) + s.Database.URL = models.NewSecretURL((*commoncfg.URL)(&migrationTestDBURL)) if overrideFn != nil { overrideFn(c, s) } }) - if c == KindFixtures { - _, filename, _, ok := runtime.Caller(1) - if !ok { - t.Fatal("could not get runtime.Caller(1)") - } - filepath := path.Join(path.Dir(filename), "../../../store/fixtures/fixtures.sql") - fixturesSQL, err := os.ReadFile(filepath) - require.NoError(t, err) - _, err = db.Exec(string(fixturesSQL)) - require.NoError(t, err) - } - return gcfg, db } diff --git a/deployment/go.mod b/deployment/go.mod index 990b3e148dd..3e06dcd4dd7 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -33,7 +33,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20250121222331-a7010b4b8ce5 diff --git a/deployment/go.sum b/deployment/go.sum index 44f19c1c81e..e0575ed2b07 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1398,8 +1398,8 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/evm/README.md b/evm/README.md index 75fe0b42279..59e57caed51 100644 --- a/evm/README.md +++ b/evm/README.md @@ -1,4 +1,4 @@ # chainlink/evm This directory tree is a temporary location for code being extracted to another module, in another repo. -Packages in this tree must not import packages outside of this tree. +Packages in this tree must not import packages outside of this tree (except for `core/gethwrappers/`). diff --git a/evm/client/clienttest/clienttest.go b/evm/client/clienttest/clienttest.go index fc774d287e6..6a67b4b20a8 100644 --- a/evm/client/clienttest/clienttest.go +++ b/evm/client/clienttest/clienttest.go @@ -18,7 +18,6 @@ func NewClientWithDefaultChainID(t *testing.T) *Client { return c } -// TODO move to clienttest? type MockEth struct { EthClient *Client CheckFilterLogs func(int64, int64) diff --git a/evm/testutils/sql.go b/evm/testutils/sql.go index 4ce4cd9d87a..3c2e2a82d51 100644 --- a/evm/testutils/sql.go +++ b/evm/testutils/sql.go @@ -1,13 +1,19 @@ package testutils import ( + "net/url" "os" + "strings" "testing" + "time" + "github.com/google/uuid" "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/pg" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/sqltest" "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" @@ -31,3 +37,30 @@ func SkipShortDB(tb testing.TB) { func MustExec(t *testing.T, ds sqlutil.DataSource, stmt string, args ...interface{}) { require.NoError(t, utils.JustError(ds.ExecContext(Context(t), stmt, args...))) } + +// pristineDBName is a clean copy of test DB with migrations. +const pristineDBName = "chainlink_test_pristine" //TODO update when splitting schemas + +// NewIndependentSqlxDB return a new independent test database, which does not use txdb and therefore supports txs etc. +// Use this with caution, as it is much more costly than NewSqlxDB. +func NewIndependentSqlxDB(t testing.TB) *sqlx.DB { + SkipShortDB(t) + + ctx := tests.Context(t) + + dbURL, err := url.Parse(sqltest.TestURL(t)) + require.NoError(t, err) + dbName := "chainlink_test_" + strings.ReplaceAll(uuid.NewString(), "-", "") + newDBURL := sqltest.CreateOrReplace(t, *dbURL, dbName, pristineDBName) + + db, err := pg.DBConfig{ + IdleInTxSessionTimeout: time.Hour, + LockTimeout: 15 * time.Second, + MaxOpenConns: 100, + MaxIdleConns: 10, + }.New(ctx, newDBURL.String(), pg.DriverPostgres) + require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, db.Close()) }) + + return db +} diff --git a/go.mod b/go.mod index 27cfc00056a..9af68f0aa4c 100644 --- a/go.mod +++ b/go.mod @@ -79,7 +79,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 github.com/smartcontractkit/chainlink-feeds v0.1.1 diff --git a/go.sum b/go.sum index 36d35039fa4..47aa94e08d5 100644 --- a/go.sum +++ b/go.sum @@ -1156,8 +1156,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index a0f26012169..cc1cb7fc05a 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -49,7 +49,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-testing-framework/framework v0.4.7 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 0a2ac5c1be9..276597c23ff 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1426,8 +1426,8 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 43b95dd009b..1bf6c72d5c9 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -29,7 +29,7 @@ require ( github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.21 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.10 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.2 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 1352a738b7c..221bad9fbbd 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1413,8 +1413,8 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d h1:ez+JYyIJ7pUR0/OnnU3AIKaC0Re85qB2fkA1NfiAnuA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130104613-82e554262f7d/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc/go.mod h1:2iGmU7fkVsy21Sw8D+OhtYekHLUlJKHzwePKcxIx3Ac= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 h1:CvDfgWoLoYPapOumE/UZCplfCu5oNmy9BuH+6V6+fJ8= diff --git a/internal/testdb/testdb.go b/internal/testdb/testdb.go index 88664e87f99..64c04c01908 100644 --- a/internal/testdb/testdb.go +++ b/internal/testdb/testdb.go @@ -1,13 +1,10 @@ package testdb import ( - "database/sql" - "errors" - "fmt" "net/url" - "strings" + "testing" - pgcommon "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/pg" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/sqltest" ) const ( @@ -20,62 +17,12 @@ const ( // CreateOrReplace creates a database named with a common prefix and the given suffix, and returns the URL. // If the database already exists, it will be dropped and re-created. // If withTemplate is true, the pristine DB will be used as a template. -func CreateOrReplace(parsed url.URL, suffix string, withTemplate bool) (string, error) { - if parsed.Path == "" { - return "", errors.New("path missing from database URL") - } - +func CreateOrReplace(t testing.TB, parsed url.URL, suffix string, withTemplate bool) url.URL { // Match the naming schema that our dangling DB cleanup methods expect dbname := TestDBNamePrefix + suffix - if l := len(dbname); l > 63 { - return "", fmt.Errorf("dbname %v too long (%d), max is 63 bytes. Try a shorter suffix", dbname, l) - } - // Cannot drop test database if we are connected to it, so we must connect - // to a different one. 'postgres' should be present on all postgres installations - parsed.Path = "/postgres" - db, err := sql.Open(pgcommon.DriverPostgres, parsed.String()) - if err != nil { - return "", fmt.Errorf("in order to drop the test database, we need to connect to a separate database"+ - " called 'postgres'. But we are unable to open 'postgres' database: %+v\n", err) - } - defer db.Close() - - _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", dbname)) - if err != nil { - return "", fmt.Errorf("unable to drop postgres migrations test database: %v", err) - } + var template string if withTemplate { - _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s WITH TEMPLATE %s", dbname, PristineDBName)) - } else { - _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", dbname)) - } - if err != nil { - return "", fmt.Errorf("unable to create postgres test database with name '%s': %v", dbname, err) - } - parsed.Path = fmt.Sprintf("/%s", dbname) - return parsed.String(), nil -} - -// Drop drops the database at the given URL. -func Drop(dbURL url.URL) error { - if dbURL.Path == "" { - return errors.New("path missing from database URL") - } - dbname := strings.TrimPrefix(dbURL.Path, "/") - - // Cannot drop test database if we are connected to it, so we must connect - // to a different one. 'postgres' should be present on all postgres installations - dbURL.Path = "/postgres" - db, err := sql.Open(pgcommon.DriverPostgres, dbURL.String()) - if err != nil { - return fmt.Errorf("in order to drop the test database, we need to connect to a separate database"+ - " called 'postgres'. But we are unable to open 'postgres' database: %+v\n", err) - } - defer db.Close() - - _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", dbname)) - if err != nil { - return fmt.Errorf("unable to drop postgres migrations test database: %v", err) + template = PristineDBName } - return nil + return sqltest.CreateOrReplace(t, parsed, dbname, template) } diff --git a/main_test.go b/main_test.go index f5efe1a2957..a4984e3f7b7 100644 --- a/main_test.go +++ b/main_test.go @@ -60,7 +60,7 @@ func TestScripts(t *testing.T) { testscript.Run(t, testscript.Params{ Dir: path, - Setup: commonEnv, + Setup: commonEnv(t), ContinueOnError: true, // UpdateScripts: true, // uncomment to update golden files }) @@ -74,47 +74,46 @@ func TestScripts(t *testing.T) { // isIntegrationBuild is toggled true by a func init() with a //go:build integration gate var isIntegrationBuild = false -func commonEnv(te *testscript.Env) error { - if _, err := os.Stat(integrationBuildName); err == nil && !isIntegrationBuild { - te.T().Skip("integration test") - return nil - } +func commonEnv(t testing.TB) func(*testscript.Env) error { + return func(te *testscript.Env) error { + if _, err := os.Stat(integrationBuildName); err == nil && !isIntegrationBuild { + te.T().Skip("integration test") + return nil + } - te.Setenv("HOME", "$WORK/home") - te.Setenv("VERSION", static.Version) - te.Setenv("COMMIT_SHA", static.Sha) + te.Setenv("HOME", "$WORK/home") + te.Setenv("VERSION", static.Version) + te.Setenv("COMMIT_SHA", static.Sha) - b, err := os.ReadFile(filepath.Join(te.WorkDir, testPortName)) - if err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to read file %s: %w", testPortName, err) - } else if err == nil { - envVarName := strings.TrimSpace(string(b)) - te.T().Log("test port requested:", envVarName) + b, err := os.ReadFile(filepath.Join(te.WorkDir, testPortName)) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to read file %s: %w", testPortName, err) + } else if err == nil { + envVarName := strings.TrimSpace(string(b)) + te.T().Log("test port requested:", envVarName) - port, ret, err2 := takeFreePort() - if err2 != nil { - return err2 + port, ret, err2 := takeFreePort() + if err2 != nil { + return err2 + } + te.Defer(ret) + + te.Setenv(envVarName, strconv.Itoa(port)) } - te.Defer(ret) - te.Setenv(envVarName, strconv.Itoa(port)) - } + b, err = os.ReadFile(filepath.Join(te.WorkDir, testDBName)) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to read file %s: %w", testDBName, err) + } else if err == nil { + envVarName := strings.TrimSpace(string(b)) + te.T().Log("test database requested:", envVarName) - b, err = os.ReadFile(filepath.Join(te.WorkDir, testDBName)) - if err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to read file %s: %w", testDBName, err) - } else if err == nil { - envVarName := strings.TrimSpace(string(b)) - te.T().Log("test database requested:", envVarName) + u2 := newDB(t) - u2, err2 := initDB() - if err2 != nil { - return err2 + te.Setenv(envVarName, u2) } - - te.Setenv(envVarName, u2) + return nil } - return nil } func takeFreePort() (int, func(), error) { @@ -125,16 +124,13 @@ func takeFreePort() (int, func(), error) { return ports[0], func() { freeport.Return(ports) }, nil } -func initDB() (string, error) { +func newDB(t testing.TB) string { u, err := url.Parse(string(env.DatabaseURL.Get())) if err != nil { - return "", fmt.Errorf("failed to parse url: %w", err) + t.Fatalf("failed to parse url: %v", err) } name := strings.ReplaceAll(uuid.NewString(), "-", "_") + "_test" - u2, err := testdb.CreateOrReplace(*u, name, true) - if err != nil { - return "", fmt.Errorf("failed to create DB: %w", err) - } - return u2, nil + u2 := testdb.CreateOrReplace(t, *u, name, true) + return u2.String() } From 331a2e829e836f700a48aebc23820f14032471d9 Mon Sep 17 00:00:00 2001 From: krehermann <16602512+krehermann@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:28:24 -0700 Subject: [PATCH 27/43] chore(cre deployment): reduce func scope (#16161) * delete unused code * fix scripts * move test code * seperate registry and contract set for internal use * rm dead references * slim down forwarder * cleanup --- .../changeset/append_node_capabilities.go | 31 +++++----- .../internal/append_node_capabilities.go | 20 +++---- .../internal/append_node_capabilities_test.go | 4 +- .../keystone/changeset/internal/deploy.go | 35 ++++++------ .../changeset/internal/deploy_test.go | 12 ++-- .../changeset/internal/forwarder_deployer.go | 2 +- .../keystone/changeset/internal/ocr3config.go | 3 +- .../keystone/changeset/internal/state.go | 1 + .../keystone/changeset/internal/update_don.go | 16 +++--- .../changeset/internal/update_don_test.go | 18 +++--- .../internal/update_node_capabilities.go | 20 +++---- .../internal/update_node_capabilities_test.go | 4 +- .../changeset/internal/update_nodes.go | 10 ++-- .../changeset/internal/update_nodes_test.go | 56 +++++++++---------- deployment/keystone/changeset/test/helpers.go | 8 +-- .../test/utils.go => test/registry.go} | 24 ++++---- deployment/keystone/changeset/update_don.go | 10 ++-- .../keystone/changeset/update_don_test.go | 6 +- .../changeset/update_node_capabilities.go | 40 ++++++------- deployment/keystone/changeset/update_nodes.go | 22 ++++++-- 20 files changed, 174 insertions(+), 168 deletions(-) rename deployment/keystone/changeset/{internal/test/utils.go => test/registry.go} (96%) diff --git a/deployment/keystone/changeset/append_node_capabilities.go b/deployment/keystone/changeset/append_node_capabilities.go index 9ae1923d270..826ba4601f7 100644 --- a/deployment/keystone/changeset/append_node_capabilities.go +++ b/deployment/keystone/changeset/append_node_capabilities.go @@ -21,7 +21,7 @@ type AppendNodeCapabilitiesRequest = MutateNodeCapabilitiesRequest // AppendNodeCapabilities adds any new capabilities to the registry, merges the new capabilities with the existing capabilities // of the node, and updates the nodes in the registry host the union of the new and existing capabilities. func AppendNodeCapabilities(env deployment.Environment, req *AppendNodeCapabilitiesRequest) (deployment.ChangesetOutput, error) { - c, err := req.convert(env) + c, contractSet, err := req.convert(env) if err != nil { return deployment.ChangesetOutput{}, err } @@ -35,10 +35,10 @@ func AppendNodeCapabilities(env deployment.Environment, req *AppendNodeCapabilit return out, errors.New("expected MCMS operation to be non-nil") } timelocksPerChain := map[uint64]common.Address{ - c.Chain.Selector: c.ContractSet.Timelock.Address(), + c.Chain.Selector: contractSet.Timelock.Address(), } proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - c.Chain.Selector: c.ContractSet.ProposerMcm, + c.Chain.Selector: contractSet.ProposerMcm, } proposal, err := proposalutils.BuildProposalFromBatches( @@ -56,27 +56,24 @@ func AppendNodeCapabilities(env deployment.Environment, req *AppendNodeCapabilit return out, nil } -func (req *AppendNodeCapabilitiesRequest) convert(e deployment.Environment) (*internal.AppendNodeCapabilitiesRequest, error) { - if err := req.Validate(); err != nil { - return nil, fmt.Errorf("failed to validate UpdateNodeCapabilitiesRequest: %w", err) - } - registryChain, ok := e.Chains[req.RegistryChainSel] - if !ok { - return nil, fmt.Errorf("registry chain selector %d does not exist in environment", req.RegistryChainSel) +func (req *AppendNodeCapabilitiesRequest) convert(e deployment.Environment) (*internal.AppendNodeCapabilitiesRequest, *ContractSet, error) { + if err := req.Validate(e); err != nil { + return nil, nil, fmt.Errorf("failed to validate UpdateNodeCapabilitiesRequest: %w", err) } + registryChain := e.Chains[req.RegistryChainSel] // exists because of the validation above resp, err := internal.GetContractSets(e.Logger, &internal.GetContractSetsRequest{ Chains: map[uint64]deployment.Chain{req.RegistryChainSel: registryChain}, AddressBook: e.ExistingAddresses, }) if err != nil { - return nil, fmt.Errorf("failed to get contract sets: %w", err) + return nil, nil, fmt.Errorf("failed to get contract sets: %w", err) } - contracts := resp.ContractSets[req.RegistryChainSel] + contractSet := resp.ContractSets[req.RegistryChainSel] return &internal.AppendNodeCapabilitiesRequest{ - Chain: registryChain, - ContractSet: &contracts, - P2pToCapabilities: req.P2pToCapabilities, - UseMCMS: req.UseMCMS(), - }, nil + Chain: registryChain, + CapabilitiesRegistry: contractSet.CapabilitiesRegistry, + P2pToCapabilities: req.P2pToCapabilities, + UseMCMS: req.UseMCMS(), + }, &contractSet, nil } diff --git a/deployment/keystone/changeset/internal/append_node_capabilities.go b/deployment/keystone/changeset/internal/append_node_capabilities.go index a87688b5427..85203120063 100644 --- a/deployment/keystone/changeset/internal/append_node_capabilities.go +++ b/deployment/keystone/changeset/internal/append_node_capabilities.go @@ -12,8 +12,8 @@ import ( ) type AppendNodeCapabilitiesRequest struct { - Chain deployment.Chain - ContractSet *ContractSet + Chain deployment.Chain + CapabilitiesRegistry *kcr.CapabilitiesRegistry P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability UseMCMS bool @@ -23,7 +23,7 @@ func (req *AppendNodeCapabilitiesRequest) Validate() error { if len(req.P2pToCapabilities) == 0 { return errors.New("p2pToCapabilities is empty") } - if req.ContractSet.CapabilitiesRegistry == nil { + if req.CapabilitiesRegistry == nil { return errors.New("registry is nil") } return nil @@ -37,7 +37,7 @@ func AppendNodeCapabilitiesImpl(lggr logger.Logger, req *AppendNodeCapabilitiesR // for each node, merge the new capabilities with the existing ones and update the node updatesByPeer := make(map[p2pkey.PeerID]NodeUpdate) for p2pID, caps := range req.P2pToCapabilities { - caps, err := AppendCapabilities(lggr, req.ContractSet.CapabilitiesRegistry, req.Chain, []p2pkey.PeerID{p2pID}, caps) + caps, err := AppendCapabilities(lggr, req.CapabilitiesRegistry, req.Chain, []p2pkey.PeerID{p2pID}, caps) if err != nil { return nil, fmt.Errorf("failed to append capabilities for p2p %s: %w", p2pID, err) } @@ -49,17 +49,17 @@ func AppendNodeCapabilitiesImpl(lggr logger.Logger, req *AppendNodeCapabilitiesR for _, cap := range req.P2pToCapabilities { capabilities = append(capabilities, cap...) } - op, err := AddCapabilities(lggr, req.ContractSet.CapabilitiesRegistry, req.Chain, capabilities, req.UseMCMS) + op, err := AddCapabilities(lggr, req.CapabilitiesRegistry, req.Chain, capabilities, req.UseMCMS) if err != nil { return nil, fmt.Errorf("failed to add capabilities: %w", err) } updateNodesReq := &UpdateNodesRequest{ - Chain: req.Chain, - ContractSet: req.ContractSet, - P2pToUpdates: updatesByPeer, - UseMCMS: req.UseMCMS, - Ops: op, + Chain: req.Chain, + CapabilitiesRegistry: req.CapabilitiesRegistry, + P2pToUpdates: updatesByPeer, + UseMCMS: req.UseMCMS, + Ops: op, } resp, err := UpdateNodes(lggr, updateNodesReq) if err != nil { diff --git a/deployment/keystone/changeset/internal/append_node_capabilities_test.go b/deployment/keystone/changeset/internal/append_node_capabilities_test.go index 6d26133195d..440c3917341 100644 --- a/deployment/keystone/changeset/internal/append_node_capabilities_test.go +++ b/deployment/keystone/changeset/internal/append_node_capabilities_test.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" - kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" + kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/test" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) @@ -95,7 +95,7 @@ func TestAppendNodeCapabilities(t *testing.T) { setupResp := kstest.SetupTestRegistry(t, lggr, tt.args.initialState) tt.args.req.Chain = setupResp.Chain - tt.args.req.ContractSet = setupResp.ContractSet + tt.args.req.CapabilitiesRegistry = setupResp.CapabilitiesRegistry got, err := internal.AppendNodeCapabilitiesImpl(tt.args.lggr, tt.args.req) if (err != nil) != tt.wantErr { diff --git a/deployment/keystone/changeset/internal/deploy.go b/deployment/keystone/changeset/internal/deploy.go index be4c3a192b8..ef8f138e743 100644 --- a/deployment/keystone/changeset/internal/deploy.go +++ b/deployment/keystone/changeset/internal/deploy.go @@ -323,12 +323,11 @@ func ConfigureOCR3Contract(env *deployment.Environment, chainSel uint64, dons [] } _, err = configureOCR3contract(configureOCR3Request{ - cfg: cfg, - chain: registryChain, - contract: contract, - nodes: don.Nodes, - contractSet: &contracts, - ocrSecrets: env.OCRSecrets, + cfg: cfg, + chain: registryChain, + contract: contract, + nodes: don.Nodes, + ocrSecrets: env.OCRSecrets, }) if err != nil { return fmt.Errorf("failed to configure OCR3 contract for don %s: %w", don.Name, err) @@ -386,14 +385,13 @@ func ConfigureOCR3ContractFromJD(env *deployment.Environment, cfg ConfigureOCR3C return nil, err } r, err := configureOCR3contract(configureOCR3Request{ - cfg: cfg.OCR3Config, - chain: registryChain, - contract: contract, - nodes: nodes, - dryRun: cfg.DryRun, - contractSet: &contracts, - useMCMS: cfg.UseMCMS, - ocrSecrets: env.OCRSecrets, + cfg: cfg.OCR3Config, + chain: registryChain, + contract: contract, + nodes: nodes, + dryRun: cfg.DryRun, + useMCMS: cfg.UseMCMS, + ocrSecrets: env.OCRSecrets, }) if err != nil { return nil, err @@ -514,8 +512,8 @@ type RegisterNOPSRequest struct { } type RegisterNOPSResponse struct { - Nops []*capabilities_registry.CapabilitiesRegistryNodeOperatorAdded - Ops *timelock.BatchChainOperation + Nops []*capabilities_registry.CapabilitiesRegistryNodeOperatorAdded // if UseMCMS is false, a list of added node operators is returned + Ops *timelock.BatchChainOperation // if UseMCMS is true, a batch proposal is returned and no transaction is confirmed on chain. } func RegisterNOPS(ctx context.Context, lggr logger.Logger, req RegisterNOPSRequest) (*RegisterNOPSResponse, error) { @@ -1047,12 +1045,11 @@ func containsAllDONs(donInfos []capabilities_registry.CapabilitiesRegistryDONInf // configureForwarder sets the config for the forwarder contract on the chain for all Dons that accept workflows // dons that don't accept workflows are not registered with the forwarder -func configureForwarder(lggr logger.Logger, chain deployment.Chain, contractSet ContractSet, dons []RegisteredDon, useMCMS bool) (map[uint64]timelock.BatchChainOperation, error) { - if contractSet.Forwarder == nil { +func configureForwarder(lggr logger.Logger, chain deployment.Chain, fwdr *kf.KeystoneForwarder, dons []RegisteredDon, useMCMS bool) (map[uint64]timelock.BatchChainOperation, error) { + if fwdr == nil { return nil, errors.New("nil forwarder contract") } var ( - fwdr = contractSet.Forwarder opMap = make(map[uint64]timelock.BatchChainOperation) ) for _, dn := range dons { diff --git a/deployment/keystone/changeset/internal/deploy_test.go b/deployment/keystone/changeset/internal/deploy_test.go index 5b37b397026..83fcfe20e40 100644 --- a/deployment/keystone/changeset/internal/deploy_test.go +++ b/deployment/keystone/changeset/internal/deploy_test.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" - kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" + kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/test" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) @@ -21,7 +21,7 @@ func Test_RegisterNOPS(t *testing.T) { useMCMS bool lggr = logger.Test(t) setupResp = kstest.SetupTestRegistry(t, lggr, &kstest.SetupTestRegistryRequest{}) - registry = setupResp.Registry + registry = setupResp.CapabilitiesRegistry chain = setupResp.Chain nops = make([]kcr.CapabilitiesRegistryNodeOperator, 0) ) @@ -61,7 +61,7 @@ func Test_AddCapabilities(t *testing.T) { useMCMS bool lggr = logger.Test(t) setupResp = kstest.SetupTestRegistry(t, lggr, &kstest.SetupTestRegistryRequest{}) - registry = setupResp.Registry + registry = setupResp.CapabilitiesRegistry chain = setupResp.Chain capabilities = make([]kcr.CapabilitiesRegistryCapability, 0) ) @@ -114,7 +114,7 @@ func Test_RegisterNodes(t *testing.T) { P2pToCapabilities: initialp2pToCapabilities, NopToNodes: nopToNodes, }) - registry = setupResp.Registry + registry = setupResp.CapabilitiesRegistry chain = setupResp.Chain registeredCapabilities = kstest.GetRegisteredCapabilities(t, lggr, initialp2pToCapabilities, setupResp.CapabilityCache) @@ -282,7 +282,7 @@ func Test_RegisterDons(t *testing.T) { useMCMS bool lggr = logger.Test(t) setupResp = kstest.SetupTestRegistry(t, lggr, &kstest.SetupTestRegistryRequest{}) - registry = setupResp.Registry + registry = setupResp.CapabilitiesRegistry chain = setupResp.Chain ) t.Run("success create add DONs mcms proposal", func(t *testing.T) { @@ -377,7 +377,7 @@ func Test_RegisterDons(t *testing.T) { }, }, }) - regContract = setupResp.Registry + regContract = setupResp.CapabilitiesRegistry ) env := &deployment.Environment{ diff --git a/deployment/keystone/changeset/internal/forwarder_deployer.go b/deployment/keystone/changeset/internal/forwarder_deployer.go index 6e374e200d7..90a3e8cfb1d 100644 --- a/deployment/keystone/changeset/internal/forwarder_deployer.go +++ b/deployment/keystone/changeset/internal/forwarder_deployer.go @@ -88,7 +88,7 @@ func ConfigureForwardContracts(env *deployment.Environment, req ConfigureForward if !ok { return nil, fmt.Errorf("failed to get contract set for chain %d", chain.Selector) } - ops, err := configureForwarder(env.Logger, chain, contracts, req.Dons, req.UseMCMS) + ops, err := configureForwarder(env.Logger, chain, contracts.Forwarder, req.Dons, req.UseMCMS) if err != nil { return nil, fmt.Errorf("failed to configure forwarder for chain selector %d: %w", chain.Selector, err) } diff --git a/deployment/keystone/changeset/internal/ocr3config.go b/deployment/keystone/changeset/internal/ocr3config.go index d1d2e337efb..8b433189081 100644 --- a/deployment/keystone/changeset/internal/ocr3config.go +++ b/deployment/keystone/changeset/internal/ocr3config.go @@ -287,8 +287,7 @@ type configureOCR3Request struct { dryRun bool ocrSecrets deployment.OCRSecrets - useMCMS bool - contractSet *ContractSet + useMCMS bool } func (r configureOCR3Request) generateOCR3Config() (OCR2OracleConfig, error) { diff --git a/deployment/keystone/changeset/internal/state.go b/deployment/keystone/changeset/internal/state.go index 3253acaf4e4..ad81d912d0d 100644 --- a/deployment/keystone/changeset/internal/state.go +++ b/deployment/keystone/changeset/internal/state.go @@ -27,6 +27,7 @@ type GetContractSetsResponse struct { ContractSets map[uint64]ContractSet } +// TODO move this out of internal type ContractSet struct { commonchangeset.MCMSWithTimelockState OCR3 map[common.Address]*ocr3_capability.OCR3Capability diff --git a/deployment/keystone/changeset/internal/update_don.go b/deployment/keystone/changeset/internal/update_don.go index b5006358f77..8c7e77608fb 100644 --- a/deployment/keystone/changeset/internal/update_don.go +++ b/deployment/keystone/changeset/internal/update_don.go @@ -28,8 +28,8 @@ type CapabilityConfig struct { } type UpdateDonRequest struct { - Chain deployment.Chain - ContractSet *ContractSet // contract set for the given chain + Chain deployment.Chain + CapabilitiesRegistry *kcr.CapabilitiesRegistry P2PIDs []p2pkey.PeerID // this is the unique identifier for the don CapabilityConfigs []CapabilityConfig // if Config subfield is nil, a default config is used @@ -39,10 +39,10 @@ type UpdateDonRequest struct { func (r *UpdateDonRequest) AppendNodeCapabilitiesRequest() *AppendNodeCapabilitiesRequest { out := &AppendNodeCapabilitiesRequest{ - Chain: r.Chain, - ContractSet: r.ContractSet, - P2pToCapabilities: make(map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability), - UseMCMS: r.UseMCMS, + Chain: r.Chain, + CapabilitiesRegistry: r.CapabilitiesRegistry, + P2pToCapabilities: make(map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability), + UseMCMS: r.UseMCMS, } for _, p2pid := range r.P2PIDs { if _, exists := out.P2pToCapabilities[p2pid]; !exists { @@ -56,7 +56,7 @@ func (r *UpdateDonRequest) AppendNodeCapabilitiesRequest() *AppendNodeCapabiliti } func (r *UpdateDonRequest) Validate() error { - if r.ContractSet.CapabilitiesRegistry == nil { + if r.CapabilitiesRegistry == nil { return errors.New("registry is required") } if len(r.P2PIDs) == 0 { @@ -75,7 +75,7 @@ func UpdateDon(_ logger.Logger, req *UpdateDonRequest) (*UpdateDonResponse, erro return nil, fmt.Errorf("failed to validate request: %w", err) } - registry := req.ContractSet.CapabilitiesRegistry + registry := req.CapabilitiesRegistry getDonsResp, err := registry.GetDONs(&bind.CallOpts{}) if err != nil { return nil, fmt.Errorf("failed to get Dons: %w", err) diff --git a/deployment/keystone/changeset/internal/update_don_test.go b/deployment/keystone/changeset/internal/update_don_test.go index 42b032d9433..7fbdcda100d 100644 --- a/deployment/keystone/changeset/internal/update_don_test.go +++ b/deployment/keystone/changeset/internal/update_don_test.go @@ -20,7 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" kscs "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" - kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" + kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/test" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) @@ -131,16 +131,16 @@ func TestUpdateDon(t *testing.T) { } _, err := internal.AppendNodeCapabilitiesImpl(lggr, &internal.AppendNodeCapabilitiesRequest{ - Chain: testCfg.Chain, - ContractSet: testCfg.ContractSet, - P2pToCapabilities: m, + Chain: testCfg.Chain, + CapabilitiesRegistry: testCfg.CapabilitiesRegistry, + P2pToCapabilities: m, }) require.NoError(t, err) req := &internal.UpdateDonRequest{ - ContractSet: testCfg.ContractSet, - Chain: testCfg.Chain, - P2PIDs: []p2pkey.PeerID{p2p_1.PeerID(), p2p_2.PeerID(), p2p_3.PeerID(), p2p_4.PeerID()}, + CapabilitiesRegistry: testCfg.CapabilitiesRegistry, + Chain: testCfg.Chain, + P2PIDs: []p2pkey.PeerID{p2p_1.PeerID(), p2p_2.PeerID(), p2p_3.PeerID(), p2p_4.PeerID()}, CapabilityConfigs: []internal.CapabilityConfig{ {Capability: initialCap, Config: initialCapCfgB}, {Capability: capToAdd, Config: capToAddCfgB}, }, @@ -151,8 +151,8 @@ func TestUpdateDon(t *testing.T) { ConfigCount: 1, NodeP2PIds: internal.PeerIDsToBytes([]p2pkey.PeerID{p2p_1.PeerID(), p2p_2.PeerID(), p2p_3.PeerID(), p2p_4.PeerID()}), CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - {CapabilityId: kstest.MustCapabilityId(t, testCfg.Registry, initialCap), Config: initialCapCfgB}, - {CapabilityId: kstest.MustCapabilityId(t, testCfg.Registry, capToAdd), Config: capToAddCfgB}, + {CapabilityId: kstest.MustCapabilityId(t, testCfg.CapabilitiesRegistry, initialCap), Config: initialCapCfgB}, + {CapabilityId: kstest.MustCapabilityId(t, testCfg.CapabilitiesRegistry, capToAdd), Config: capToAddCfgB}, }, }, } diff --git a/deployment/keystone/changeset/internal/update_node_capabilities.go b/deployment/keystone/changeset/internal/update_node_capabilities.go index 34fb5346d5c..ce975368a1d 100644 --- a/deployment/keystone/changeset/internal/update_node_capabilities.go +++ b/deployment/keystone/changeset/internal/update_node_capabilities.go @@ -11,9 +11,9 @@ import ( ) type UpdateNodeCapabilitiesImplRequest struct { - Chain deployment.Chain - ContractSet *ContractSet - P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability + Chain deployment.Chain + CapabilitiesRegistry *kcr.CapabilitiesRegistry + P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability UseMCMS bool } @@ -22,7 +22,7 @@ func (req *UpdateNodeCapabilitiesImplRequest) Validate() error { if len(req.P2pToCapabilities) == 0 { return errors.New("p2pToCapabilities is empty") } - if req.ContractSet == nil { + if req.CapabilitiesRegistry == nil { return errors.New("registry is nil") } @@ -38,7 +38,7 @@ func UpdateNodeCapabilitiesImpl(lggr logger.Logger, req *UpdateNodeCapabilitiesI for _, cap := range req.P2pToCapabilities { capabilities = append(capabilities, cap...) } - op, err := AddCapabilities(lggr, req.ContractSet.CapabilitiesRegistry, req.Chain, capabilities, req.UseMCMS) + op, err := AddCapabilities(lggr, req.CapabilitiesRegistry, req.Chain, capabilities, req.UseMCMS) if err != nil { return nil, fmt.Errorf("failed to add capabilities: %w", err) } @@ -49,11 +49,11 @@ func UpdateNodeCapabilitiesImpl(lggr logger.Logger, req *UpdateNodeCapabilitiesI } updateNodesReq := &UpdateNodesRequest{ - Chain: req.Chain, - P2pToUpdates: p2pToUpdates, - ContractSet: req.ContractSet, - Ops: op, - UseMCMS: req.UseMCMS, + Chain: req.Chain, + P2pToUpdates: p2pToUpdates, + CapabilitiesRegistry: req.CapabilitiesRegistry, + Ops: op, + UseMCMS: req.UseMCMS, } resp, err := UpdateNodes(lggr, updateNodesReq) if err != nil { diff --git a/deployment/keystone/changeset/internal/update_node_capabilities_test.go b/deployment/keystone/changeset/internal/update_node_capabilities_test.go index 65da264dd01..560494ba09e 100644 --- a/deployment/keystone/changeset/internal/update_node_capabilities_test.go +++ b/deployment/keystone/changeset/internal/update_node_capabilities_test.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" - kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" + kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/test" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) @@ -93,7 +93,7 @@ func TestUpdateNodeCapabilities(t *testing.T) { t.Run(tt.name, func(t *testing.T) { setupResp := kstest.SetupTestRegistry(t, lggr, tt.args.initialState) tt.args.req.Chain = setupResp.Chain - tt.args.req.ContractSet = setupResp.ContractSet + tt.args.req.CapabilitiesRegistry = setupResp.CapabilitiesRegistry got, err := internal.UpdateNodeCapabilitiesImpl(tt.args.lggr, tt.args.req) if (err != nil) != tt.wantErr { diff --git a/deployment/keystone/changeset/internal/update_nodes.go b/deployment/keystone/changeset/internal/update_nodes.go index 976125e582d..4c33b3d08a3 100644 --- a/deployment/keystone/changeset/internal/update_nodes.go +++ b/deployment/keystone/changeset/internal/update_nodes.go @@ -29,8 +29,8 @@ type NodeUpdate struct { } type UpdateNodesRequest struct { - Chain deployment.Chain - ContractSet *ContractSet // contract set for the given chain + Chain deployment.Chain + CapabilitiesRegistry *kcr.CapabilitiesRegistry P2pToUpdates map[p2pkey.PeerID]NodeUpdate @@ -41,7 +41,7 @@ type UpdateNodesRequest struct { } func (req *UpdateNodesRequest) NodeParams() ([]kcr.CapabilitiesRegistryNodeParams, error) { - return makeNodeParams(req.ContractSet.CapabilitiesRegistry, req.P2pToUpdates) + return makeNodeParams(req.CapabilitiesRegistry, req.P2pToUpdates) } // P2PSignerEnc represent the key fields in kcr.CapabilitiesRegistryNodeParams @@ -79,7 +79,7 @@ func (req *UpdateNodesRequest) Validate() error { } } - if req.ContractSet.CapabilitiesRegistry == nil { + if req.CapabilitiesRegistry == nil { return errors.New("registry is nil") } @@ -110,7 +110,7 @@ func UpdateNodes(lggr logger.Logger, req *UpdateNodesRequest) (*UpdateNodesRespo if req.UseMCMS { txOpts = deployment.SimTransactOpts() } - registry := req.ContractSet.CapabilitiesRegistry + registry := req.CapabilitiesRegistry tx, err := registry.UpdateNodes(txOpts, params) if err != nil { err = deployment.DecodeErr(kcr.CapabilitiesRegistryABI, err) diff --git a/deployment/keystone/changeset/internal/update_nodes_test.go b/deployment/keystone/changeset/internal/update_nodes_test.go index fc565c699b2..c26c57ab4f6 100644 --- a/deployment/keystone/changeset/internal/update_nodes_test.go +++ b/deployment/keystone/changeset/internal/update_nodes_test.go @@ -22,17 +22,17 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" - kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" + kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/test" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) func Test_UpdateNodesRequest_validate(t *testing.T) { type fields struct { - p2pToUpdates map[p2pkey.PeerID]internal.NodeUpdate - nopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc - chain deployment.Chain - contractSet *internal.ContractSet + p2pToUpdates map[p2pkey.PeerID]internal.NodeUpdate + nopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc + chain deployment.Chain + capabilitiesRegistry *kcr.CapabilitiesRegistry } tests := []struct { name string @@ -42,10 +42,10 @@ func Test_UpdateNodesRequest_validate(t *testing.T) { { name: "err", fields: fields{ - p2pToUpdates: map[p2pkey.PeerID]internal.NodeUpdate{}, - nopToNodes: nil, - chain: deployment.Chain{}, - contractSet: nil, + p2pToUpdates: map[p2pkey.PeerID]internal.NodeUpdate{}, + nopToNodes: nil, + chain: deployment.Chain{}, + capabilitiesRegistry: nil, }, wantErr: true, }, @@ -57,9 +57,9 @@ func Test_UpdateNodesRequest_validate(t *testing.T) { EncryptionPublicKey: "jk", }, }, - nopToNodes: nil, - chain: deployment.Chain{}, - contractSet: nil, + nopToNodes: nil, + chain: deployment.Chain{}, + capabilitiesRegistry: nil, }, wantErr: true, }, @@ -71,9 +71,9 @@ func Test_UpdateNodesRequest_validate(t *testing.T) { EncryptionPublicKey: "aabb", }, }, - nopToNodes: nil, - chain: deployment.Chain{}, - contractSet: nil, + nopToNodes: nil, + chain: deployment.Chain{}, + capabilitiesRegistry: nil, }, wantErr: true, }, @@ -81,9 +81,9 @@ func Test_UpdateNodesRequest_validate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req := &internal.UpdateNodesRequest{ - P2pToUpdates: tt.fields.p2pToUpdates, - Chain: tt.fields.chain, - ContractSet: tt.fields.contractSet, + P2pToUpdates: tt.fields.p2pToUpdates, + Chain: tt.fields.chain, + CapabilitiesRegistry: tt.fields.capabilitiesRegistry, } if err := req.Validate(); (err != nil) != tt.wantErr { t.Errorf("internal.UpdateNodesRequest.validate() error = %v, wantErr %v", err, tt.wantErr) @@ -351,8 +351,8 @@ func TestUpdateNodes(t *testing.T) { EncryptionPublicKey: newKeyStr, }, }, - Chain: chain, - ContractSet: nil, // set in test to ensure no conflicts + Chain: chain, + CapabilitiesRegistry: nil, // set in test to ensure no conflicts }, nopsToNodes: map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc{ testNop(t, "nop1"): []*internal.P2PSignerEnc{ @@ -386,8 +386,8 @@ func TestUpdateNodes(t *testing.T) { Signer: [32]byte{0: 2, 1: 3}, }, }, - Chain: chain, - ContractSet: nil, // set in test to ensure no conflicts + Chain: chain, + CapabilitiesRegistry: nil, // set in test to ensure no conflicts }, nopsToNodes: map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc{ testNop(t, "nop1"): []*internal.P2PSignerEnc{ @@ -473,8 +473,8 @@ func TestUpdateNodes(t *testing.T) { P2pToCapabilities: initMap, NopToNodes: tt.args.nopsToNodes, }) - registry := setupResp.Registry - tt.args.req.ContractSet = setupResp.ContractSet + registry := setupResp.CapabilitiesRegistry + tt.args.req.CapabilitiesRegistry = setupResp.CapabilitiesRegistry tt.args.req.Chain = setupResp.Chain id, err := registry.GetHashedCapabilityId(&bind.CallOpts{}, phonyCap.LabelledName, phonyCap.Version) @@ -567,7 +567,7 @@ func TestUpdateNodes(t *testing.T) { P2pToCapabilities: p2pToCapabilitiesInitial, NopToNodes: nopToNodes, }) - registry := setupResp.Registry + registry := setupResp.CapabilitiesRegistry chain := setupResp.Chain // there should be two capabilities @@ -592,8 +592,8 @@ func TestUpdateNodes(t *testing.T) { Capabilities: toRegister, }, }, - Chain: chain, - ContractSet: setupResp.ContractSet, + Chain: chain, + CapabilitiesRegistry: setupResp.CapabilitiesRegistry, } _, err = internal.UpdateNodes(lggr, req) require.NoError(t, err) @@ -641,7 +641,7 @@ func TestAppendCapabilities(t *testing.T) { P2pToCapabilities: capMap, NopToNodes: nopToNodes, }) - registry := setupResp.Registry + registry := setupResp.CapabilitiesRegistry chain := setupResp.Chain info, err := registry.GetNode(&bind.CallOpts{}, testPeerID(t, "peerID_1")) diff --git a/deployment/keystone/changeset/test/helpers.go b/deployment/keystone/changeset/test/helpers.go index 8408b1d9bcf..cb2f8c3b489 100644 --- a/deployment/keystone/changeset/test/helpers.go +++ b/deployment/keystone/changeset/test/helpers.go @@ -24,7 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/environment/memory" kschangeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" - kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" + "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/workflowregistry" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -151,9 +151,9 @@ func SetupTestEnv(t *testing.T, c TestConfig) TestEnv { assetNodes := memory.NewNodes(t, zapcore.InfoLevel, assetChains, nil, c.AssetDonConfig.N, 0, crConfig) require.Len(t, assetNodes, c.AssetDonConfig.N) - ocr3CapCfg := kstest.GetDefaultCapConfig(t, internal.OCR3Cap) - writerChainCapCfg := kstest.GetDefaultCapConfig(t, internal.WriteChainCap) - streamTriggerChainCapCfg := kstest.GetDefaultCapConfig(t, internal.StreamTriggerCap) + ocr3CapCfg := GetDefaultCapConfig(t, internal.OCR3Cap) + writerChainCapCfg := GetDefaultCapConfig(t, internal.WriteChainCap) + streamTriggerChainCapCfg := GetDefaultCapConfig(t, internal.StreamTriggerCap) // TODO: partition nodes into multiple nops diff --git a/deployment/keystone/changeset/internal/test/utils.go b/deployment/keystone/changeset/test/registry.go similarity index 96% rename from deployment/keystone/changeset/internal/test/utils.go rename to deployment/keystone/changeset/test/registry.go index f5d078e7521..88e2358a77e 100644 --- a/deployment/keystone/changeset/internal/test/utils.go +++ b/deployment/keystone/changeset/test/registry.go @@ -42,13 +42,15 @@ type SetupTestRegistryRequest struct { } type SetupTestRegistryResponse struct { - Registry *capabilities_registry.CapabilitiesRegistry - Chain deployment.Chain - RegistrySelector uint64 - ContractSet *internal.ContractSet - CapabilityCache *CapabilityCache + CapabilitiesRegistry *capabilities_registry.CapabilitiesRegistry + Chain deployment.Chain + RegistrySelector uint64 + CapabilityCache *CapabilityCache } +// SetupTestRegistry deploys a capabilities registry to the given chain +// and adds the given capabilities and node operators +// It can be used in tests that mutate the registry without any other setup such as actual nodes, dons, jobs, etc. func SetupTestRegistry(t *testing.T, lggr logger.Logger, req *SetupTestRegistryRequest) *SetupTestRegistryResponse { chain := testChain(t) @@ -75,18 +77,14 @@ func SetupTestRegistry(t *testing.T, lggr logger.Logger, req *SetupTestRegistryR addDons(t, lggr, chain, registry, capCache, req.Dons) return &SetupTestRegistryResponse{ - Registry: registry, - Chain: chain, - RegistrySelector: chain.Selector, - ContractSet: &internal.ContractSet{ - CapabilitiesRegistry: registry, - }, - CapabilityCache: capCache, + CapabilitiesRegistry: registry, + Chain: chain, + RegistrySelector: chain.Selector, + CapabilityCache: capCache, } } // ToNodeParams transforms a map of node operators to nops and a map of node p2pID to capabilities -// into a slice of node params required to register the nodes. The number of capabilities // must match the number of nodes. func ToNodeParams(t *testing.T, nop2Nodes map[capabilities_registry.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc, diff --git a/deployment/keystone/changeset/update_don.go b/deployment/keystone/changeset/update_don.go index 47cb7c82507..6f168bb55d6 100644 --- a/deployment/keystone/changeset/update_don.go +++ b/deployment/keystone/changeset/update_don.go @@ -108,10 +108,10 @@ func updateDonRequest(env deployment.Environment, r *UpdateDonRequest) (*interna contractSet := resp.ContractSets[r.RegistryChainSel] return &internal.UpdateDonRequest{ - Chain: env.Chains[r.RegistryChainSel], - ContractSet: &contractSet, - P2PIDs: r.P2PIDs, - CapabilityConfigs: r.CapabilityConfigs, - UseMCMS: r.UseMCMS(), + Chain: env.Chains[r.RegistryChainSel], + CapabilitiesRegistry: contractSet.CapabilitiesRegistry, + P2PIDs: r.P2PIDs, + CapabilityConfigs: r.CapabilityConfigs, + UseMCMS: r.UseMCMS(), }, nil } diff --git a/deployment/keystone/changeset/update_don_test.go b/deployment/keystone/changeset/update_don_test.go index 3fadb7822e2..501afb77e21 100644 --- a/deployment/keystone/changeset/update_don_test.go +++ b/deployment/keystone/changeset/update_don_test.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" - internaltest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" + "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/test" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -31,10 +31,10 @@ func TestUpdateDon(t *testing.T) { } caps = []kcr.CapabilitiesRegistryCapability{capA, capB} ) - capACfg := internaltest.GetDefaultCapConfig(t, capA) + capACfg := test.GetDefaultCapConfig(t, capA) capACfgB, err := proto.Marshal(capACfg) require.NoError(t, err) - capBCfg := internaltest.GetDefaultCapConfig(t, capB) + capBCfg := test.GetDefaultCapConfig(t, capB) capBCfgB, err := proto.Marshal(capBCfg) require.NoError(t, err) diff --git a/deployment/keystone/changeset/update_node_capabilities.go b/deployment/keystone/changeset/update_node_capabilities.go index c96393328db..5f383936231 100644 --- a/deployment/keystone/changeset/update_node_capabilities.go +++ b/deployment/keystone/changeset/update_node_capabilities.go @@ -61,15 +61,19 @@ type MutateNodeCapabilitiesRequest struct { MCMSConfig *MCMSConfig } -func (req *MutateNodeCapabilitiesRequest) Validate() error { +func (req *MutateNodeCapabilitiesRequest) Validate(e deployment.Environment) error { if len(req.P2pToCapabilities) == 0 { return errors.New("p2pToCapabilities is empty") } _, exists := chainsel.ChainBySelector(req.RegistryChainSel) if !exists { - return fmt.Errorf("registry chain selector %d does not exist", req.RegistryChainSel) + return fmt.Errorf("invalid registry chain selector %d: selector does not exist", req.RegistryChainSel) } + _, exists = e.Chains[req.RegistryChainSel] + if !exists { + return fmt.Errorf("invalid registry chain selector %d: chain does not exist in environment", req.RegistryChainSel) + } return nil } @@ -77,37 +81,35 @@ func (req *MutateNodeCapabilitiesRequest) UseMCMS() bool { return req.MCMSConfig != nil } -func (req *MutateNodeCapabilitiesRequest) updateNodeCapabilitiesImplRequest(e deployment.Environment) (*internal.UpdateNodeCapabilitiesImplRequest, error) { - if err := req.Validate(); err != nil { - return nil, fmt.Errorf("failed to validate UpdateNodeCapabilitiesRequest: %w", err) - } - registryChain, ok := e.Chains[req.RegistryChainSel] - if !ok { - return nil, fmt.Errorf("registry chain selector %d does not exist in environment", req.RegistryChainSel) +func (req *MutateNodeCapabilitiesRequest) updateNodeCapabilitiesImplRequest(e deployment.Environment) (*internal.UpdateNodeCapabilitiesImplRequest, *ContractSet, error) { + if err := req.Validate(e); err != nil { + return nil, nil, fmt.Errorf("failed to validate UpdateNodeCapabilitiesRequest: %w", err) } + registryChain := e.Chains[req.RegistryChainSel] // exists because of the validation above resp, err := internal.GetContractSets(e.Logger, &internal.GetContractSetsRequest{ Chains: map[uint64]deployment.Chain{req.RegistryChainSel: registryChain}, AddressBook: e.ExistingAddresses, }) if err != nil { - return nil, fmt.Errorf("failed to get contract sets: %w", err) + return nil, nil, fmt.Errorf("failed to get contract sets: %w", err) } contractSet, exists := resp.ContractSets[req.RegistryChainSel] if !exists { - return nil, fmt.Errorf("contract set not found for chain %d", req.RegistryChainSel) + return nil, nil, fmt.Errorf("contract set not found for chain %d", req.RegistryChainSel) } return &internal.UpdateNodeCapabilitiesImplRequest{ - Chain: registryChain, - ContractSet: &contractSet, - P2pToCapabilities: req.P2pToCapabilities, - UseMCMS: req.UseMCMS(), - }, nil + Chain: registryChain, + CapabilitiesRegistry: contractSet.CapabilitiesRegistry, + P2pToCapabilities: req.P2pToCapabilities, + UseMCMS: req.UseMCMS(), + }, &contractSet, nil } // UpdateNodeCapabilities updates the capabilities of nodes in the registry func UpdateNodeCapabilities(env deployment.Environment, req *UpdateNodeCapabilitiesRequest) (deployment.ChangesetOutput, error) { - c, err := req.updateNodeCapabilitiesImplRequest(env) + + c, contractSet, err := req.updateNodeCapabilitiesImplRequest(env) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to convert request: %w", err) } @@ -123,10 +125,10 @@ func UpdateNodeCapabilities(env deployment.Environment, req *UpdateNodeCapabilit return out, errors.New("expected MCMS operation to be non-nil") } timelocksPerChain := map[uint64]common.Address{ - c.Chain.Selector: c.ContractSet.Timelock.Address(), + c.Chain.Selector: contractSet.Timelock.Address(), } proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - c.Chain.Selector: c.ContractSet.ProposerMcm, + c.Chain.Selector: contractSet.ProposerMcm, } proposal, err := proposalutils.BuildProposalFromBatches( diff --git a/deployment/keystone/changeset/update_nodes.go b/deployment/keystone/changeset/update_nodes.go index 4a98f8b06e9..cc7c1c08eb7 100644 --- a/deployment/keystone/changeset/update_nodes.go +++ b/deployment/keystone/changeset/update_nodes.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -30,10 +31,21 @@ type UpdateNodesRequest struct { MCMSConfig *MCMSConfig } -func (r *UpdateNodesRequest) Validate() error { +func (r *UpdateNodesRequest) Validate(e deployment.Environment) error { if r.P2pToUpdates == nil { return errors.New("P2pToUpdates must be non-nil") } + + _, exists := chainsel.ChainBySelector(r.RegistryChainSel) + if !exists { + return fmt.Errorf("invalid registry chain selector %d: selector does not exist", r.RegistryChainSel) + } + + _, exists = e.Chains[r.RegistryChainSel] + if !exists { + return fmt.Errorf("invalid registry chain selector %d: chain does not exist in environment", r.RegistryChainSel) + } + return nil } @@ -64,10 +76,10 @@ func UpdateNodes(env deployment.Environment, req *UpdateNodesRequest) (deploymen } resp, err := internal.UpdateNodes(env.Logger, &internal.UpdateNodesRequest{ - Chain: registryChain, - ContractSet: &contracts, - P2pToUpdates: req.P2pToUpdates, - UseMCMS: req.UseMCMS(), + Chain: registryChain, + CapabilitiesRegistry: contracts.CapabilitiesRegistry, + P2pToUpdates: req.P2pToUpdates, + UseMCMS: req.UseMCMS(), }) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to update don: %w", err) From 57ca0fb8f3c74fec461e2168d362b62374e26b63 Mon Sep 17 00:00:00 2001 From: Josh Weintraub <26035072+jhweintraub@users.noreply.github.com> Date: Fri, 31 Jan 2025 13:41:17 -0500 Subject: [PATCH 28/43] CCIP-5061 Fix/siloed lock release pool fixes (#16102) * minor fixes and add gethwrapper generation * remove outstanding token mechanism from burnToAddress Pool and silo pool fixes * fill in coverage gap and separate two provideLiquidity test files * Update gethwrappers * typo fixes * fix solhint file issue and changeset * [Bot] Update changeset file with jira issues * remove unnec. errors and events from token pool and better variable assignment * Update gethwrappers * gas optimization * attempt undo weird rebase issues * forge fmt * comments and minor fixes * Update gethwrappers --------- Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> --- contracts/.changeset/quiet-masks-act.md | 10 + contracts/gas-snapshots/ccip.gas-snapshot | 32 +- .../scripts/native_solc_compile_all_ccip | 2 + .../ccip/pools/BurnToAddressMintTokenPool.sol | 49 - .../ccip/pools/SiloedLockReleaseTokenPool.sol | 75 +- ...urnToAddressMintTokenPool.lockOrBurn.t.sol | 27 - ...ToAddressMintTokenPool.releaseOrMint.t.sol | 35 - ...AddressMintTokenPool.setMintedTokens.t.sol | 20 - ...ockReleaseTokenPool.provideLiquidity.t.sol | 56 +- ...easeTokenPool.provideSiloedLiquidity.t.sol | 77 + ...edLockReleaseTokenPool.setRebalancer.t.sol | 5 +- ...easeTokenPool.updateSiloDesignations.t.sol | 54 +- ...ckReleaseTokenPool.withdrawLiquidity.t.sol | 6 + .../burn_to_address_mint_token_pool.go | 3209 +++++++++++++ .../siloed_lock_release_token_pool.go | 4197 +++++++++++++++++ ...rapper-dependency-versions-do-not-edit.txt | 2 + core/gethwrappers/ccip/go_generate.go | 2 + 17 files changed, 7611 insertions(+), 247 deletions(-) create mode 100644 contracts/.changeset/quiet-masks-act.md delete mode 100644 contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.releaseOrMint.t.sol delete mode 100644 contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.setMintedTokens.t.sol create mode 100644 contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideSiloedLiquidity.t.sol create mode 100644 core/gethwrappers/ccip/generated/burn_to_address_mint_token_pool/burn_to_address_mint_token_pool.go create mode 100644 core/gethwrappers/ccip/generated/siloed_lock_release_token_pool/siloed_lock_release_token_pool.go diff --git a/contracts/.changeset/quiet-masks-act.md b/contracts/.changeset/quiet-masks-act.md new file mode 100644 index 00000000000..7a987553d9d --- /dev/null +++ b/contracts/.changeset/quiet-masks-act.md @@ -0,0 +1,10 @@ +--- +'@chainlink/contracts': patch +--- + +Comment and parameter validation fixes and remove outstandingTokens from BurnToAddressMintTokenPool #bugfix + + +PR issue: CCIP-5061 + +Solidity Review issue: CCIP-3966 \ No newline at end of file diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index 7e99289b08c..130c747ab21 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -4,9 +4,7 @@ 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) +BurnToAddressMintTokenPool_lockOrBurn:test_LockOrBurn() (gas: 235440) BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurn() (gas: 239012) BurnWithFromMintTokenPool_lockOrBurn:test_Setup() (gas: 24169) CCIPClientExample_sanity:test_ImmutableExamples() (gas: 2079619) @@ -364,20 +362,20 @@ Router_routeMessage:test_routeMessage_ExecutionEvent() (gas: 157232) Router_routeMessage:test_routeMessage_ManualExec() (gas: 34881) 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) +SiloedLockReleaseTokenPool_provideLiquidity:test_provideLiquidity() (gas: 89627) +SiloedLockReleaseTokenPool_provideSiloedLiquidity:test_SiloedChain() (gas: 82328) +SiloedLockReleaseTokenPool_provideSiloedLiquidity:test_UnsiloedChain() (gas: 81889) +SiloedLockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_RevertsWhen_InsufficientLiquidity_SiloedChain() (gas: 109975) +SiloedLockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_RevertsWhen_InsufficientLiquidity_UnsiloedChain() (gas: 113535) +SiloedLockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_SiloedChain() (gas: 262243) +SiloedLockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_UnsiloedChain() (gas: 263296) +SiloedLockReleaseTokenPool_setRebalancer:test_setRebalancer_UnsiloedChains() (gas: 23661) +SiloedLockReleaseTokenPool_setRebalancer:test_setSiloRebalancer() (gas: 27540) +SiloedLockReleaseTokenPool_updateSiloDesignations:test_updateSiloDesignations() (gas: 135167) +SiloedLockReleaseTokenPool_withdrawLiqudity:test_withdrawLiquidity_RevertsWhen_LegacyFunctionSelectorUnauthorized() (gas: 16067) +SiloedLockReleaseTokenPool_withdrawLiqudity:test_withdrawLiquidity_SiloedFunds() (gas: 70845) +SiloedLockReleaseTokenPool_withdrawLiqudity:test_withdrawLiquidity_UnsiloedFunds_LegacyFunctionSelector() (gas: 72904) +SiloedLockReleaseTokenPool_withdrawLiqudity:test_withdrawSiloedLiquidity_UnsiloedFunds() (gas: 70058) TokenAdminRegistry_acceptAdminRole:test_acceptAdminRole() (gas: 44236) TokenAdminRegistry_addRegistryModule:test_addRegistryModule() (gas: 67093) TokenAdminRegistry_getAllConfiguredTokens:test_getAllConfiguredTokens_outOfBounds() (gas: 11363) diff --git a/contracts/scripts/native_solc_compile_all_ccip b/contracts/scripts/native_solc_compile_all_ccip index 416e079ac7f..b6c94ea883c 100755 --- a/contracts/scripts/native_solc_compile_all_ccip +++ b/contracts/scripts/native_solc_compile_all_ccip @@ -73,8 +73,10 @@ compileContract pools/LockReleaseTokenPool compileContract pools/BurnMintTokenPool compileContract pools/BurnFromMintTokenPool compileContract pools/BurnWithFromMintTokenPool +compileContract pools/BurnToAddressMintTokenPool compileContract pools/TokenPool compileContract pools/USDC/USDCTokenPool +compileContract pools/SiloedLockReleaseTokenPool # Test helpers compileContract test/helpers/BurnMintERC677Helper diff --git a/contracts/src/v0.8/ccip/pools/BurnToAddressMintTokenPool.sol b/contracts/src/v0.8/ccip/pools/BurnToAddressMintTokenPool.sol index 563375f099a..b32dfed183b 100644 --- a/contracts/src/v0.8/ccip/pools/BurnToAddressMintTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/BurnToAddressMintTokenPool.sol @@ -4,7 +4,6 @@ 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"; @@ -18,10 +17,6 @@ import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/tok 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 @@ -29,12 +24,6 @@ contract BurnToAddressMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersio /// 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( @@ -48,32 +37,12 @@ contract BurnToAddressMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersio 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); } @@ -82,22 +51,4 @@ contract BurnToAddressMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersio 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 index adb3a452957..0571e427860 100644 --- a/contracts/src/v0.8/ccip/pools/SiloedLockReleaseTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/SiloedLockReleaseTokenPool.sol @@ -17,9 +17,10 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { error InsufficientLiquidity(uint256 availableLiquidity, uint256 requestedAmount); error ChainNotSiloed(uint64 remoteChainSelector); error InvalidChainSelector(uint64 remoteChainSelector); + error LiquidityAmountCannotBeZero(); event LiquidityAdded(uint64 remoteChainSelector, address indexed provider, uint256 amount); - event LiquidityRemoved(uint64 remoteChainSelector, address indexed provider, uint256 amount); + event LiquidityRemoved(uint64 remoteChainSelector, address indexed remover, uint256 amount); event ChainUnsiloed(uint64 remoteChainSelector, uint256 amountUnsiloed); event ChainSiloed(uint64 remoteChainSelector, address rebalancer); event SiloRebalancerSet(uint64 indexed remoteChainSelector, address oldRebalancer, address newRebalancer); @@ -95,13 +96,16 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { // Save gas by using storage instead of memory as a value may need to be updated. SiloConfig storage remoteConfig = s_chainConfigs[releaseOrMintIn.remoteChainSelector]; + // Since remoteConfig.isSiloed is used more than once, caching in memory saves gas instead of multiple SLOADs. + bool isSiloed = remoteConfig.isSiloed; + // Prevent A silent underflow by explicitly ensuring that enough funds are available to release - uint256 availableLiquidity = remoteConfig.isSiloed ? remoteConfig.tokenBalance : s_unsiloedTokenBalance; + uint256 availableLiquidity = 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) { + if (isSiloed) { remoteConfig.tokenBalance -= localAmount; } else { s_unsiloedTokenBalance -= localAmount; @@ -115,16 +119,6 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { 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, @@ -145,11 +139,24 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { return s_unsiloedTokenBalance; } + // ================================================================ + // │ Chain Management │ + // ================================================================ + + /// @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 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. + /// @param adds A list of chain selectors to enable Siloing. 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]); @@ -167,13 +174,12 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { 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); + if (adds[i].remoteChainSelector == 0 || s_chainConfigs[adds[i].remoteChainSelector].isSiloed) { + revert InvalidChainSelector(adds[i].remoteChainSelector); } - SiloConfig memory newConfig = SiloConfig({tokenBalance: 0, rebalancer: adds[i].rebalancer, isSiloed: true}); - - s_chainConfigs[adds[i].remoteChainSelector] = newConfig; + s_chainConfigs[adds[i].remoteChainSelector] = + SiloConfig({tokenBalance: 0, rebalancer: adds[i].rebalancer, isSiloed: true}); emit ChainSiloed(adds[i].remoteChainSelector, adds[i].rebalancer); } @@ -181,11 +187,11 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { /// @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. + /// @return The current liquidity manager for the given siloed chain, or the unsiloed rebalancer if the chain is not siloed. function getSiloRebalancer( uint64 remoteChainSelector ) public view returns (address) { - SiloConfig memory remoteConfig = s_chainConfigs[remoteChainSelector]; + SiloConfig storage remoteConfig = s_chainConfigs[remoteChainSelector]; if (remoteConfig.isSiloed) { return remoteConfig.rebalancer; } @@ -193,20 +199,26 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { return s_rebalancer; } + /// @notice Gets the rebalancer for the unsiloed chains. + /// @return The current liquidity manager for the unsiloed chains. + function getRebalancer() external view returns (address) { + 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]; + SiloConfig storage remoteConfig = s_chainConfigs[remoteChainSelector]; if (!remoteConfig.isSiloed) revert ChainNotSiloed(remoteChainSelector); address oldRebalancer = remoteConfig.rebalancer; - s_chainConfigs[remoteChainSelector].rebalancer = newRebalancer; + remoteConfig.rebalancer = newRebalancer; - emit SiloRebalancerSet(remoteChainSelector, newRebalancer, oldRebalancer); + emit SiloRebalancerSet(remoteChainSelector, oldRebalancer, newRebalancer); } /// @notice Sets the Rebalancer address for unsiloed chains. @@ -219,15 +231,20 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { s_rebalancer = newRebalancer; - emit UnsiloedRebalancerSet(newRebalancer, oldRebalancer); + emit UnsiloedRebalancerSet(oldRebalancer, newRebalancer); } + // ================================================================ + // │ Provide Liquidity │ + // ================================================================ + /// @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 { + if (remoteChainSelector == 0) revert InvalidChainSelector(0); _provideLiquidity(remoteChainSelector, amount); } @@ -242,6 +259,7 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { } function _provideLiquidity(uint64 remoteChainSelector, uint256 amount) internal { + if (amount == 0) revert LiquidityAmountCannotBeZero(); 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. @@ -257,6 +275,10 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { emit LiquidityAdded(remoteChainSelector, msg.sender, amount); } + // ================================================================ + // │ Withdraw Liquidity │ + // ================================================================ + /// @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. @@ -277,6 +299,7 @@ contract SiloedLockReleaseTokenPool is TokenPool, ITypeAndVersion { } function _withdrawLiquidity(uint64 remoteChainSelector, uint256 amount) internal { + if (amount == 0) revert LiquidityAmountCannotBeZero(); if (msg.sender != getSiloRebalancer(remoteChainSelector)) revert Unauthorized(msg.sender); // Save gas by using storage as multiple values may need to be read/written. 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 index c5e559b2d9e..454778f11c6 100644 --- 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 @@ -2,7 +2,6 @@ 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"; @@ -11,8 +10,6 @@ contract BurnToAddressMintTokenPool_lockOrBurn is BurnToAddressMintTokenPoolSetu 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); @@ -35,29 +32,5 @@ contract BurnToAddressMintTokenPool_lockOrBurn is BurnToAddressMintTokenPoolSetu 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 deleted file mode 100644 index 508ed6bb787..00000000000 --- a/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.releaseOrMint.t.sol +++ /dev/null @@ -1,35 +0,0 @@ -// 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 deleted file mode 100644 index 11c615d8b2b..00000000000 --- a/contracts/src/v0.8/ccip/test/pools/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.setMintedTokens.t.sol +++ /dev/null @@ -1,20 +0,0 @@ -// 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/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideLiquidity.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideLiquidity.t.sol index 6af10971018..d38f0d87b7c 100644 --- 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 @@ -5,48 +5,14 @@ import {SiloedLockReleaseTokenPool} from "../../../pools/SiloedLockReleaseTokenP import {TokenPool} from "../../../pools/TokenPool.sol"; import {SiloedLockReleaseTokenPoolSetup} from "./SiloedLockReleaseTokenPoolSetup.t.sol"; -contract SiloedLockReleaseTokenPool_provideLiqudity is SiloedLockReleaseTokenPoolSetup { +contract SiloedLockReleaseTokenPool_provideLiquidity 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 { + function test_provideLiquidity() public { uint256 amount = 1e24; vm.expectEmit(); @@ -65,23 +31,7 @@ contract SiloedLockReleaseTokenPool_provideLiqudity is SiloedLockReleaseTokenPoo // 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 { + function test_RevertWhen_Unauthorized() public { vm.startPrank(UNAUTHORIZED_ADDRESS); vm.expectRevert(abi.encodeWithSelector(TokenPool.Unauthorized.selector, UNAUTHORIZED_ADDRESS)); diff --git a/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideSiloedLiquidity.t.sol b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideSiloedLiquidity.t.sol new file mode 100644 index 00000000000..167671dfad0 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.provideSiloedLiquidity.t.sol @@ -0,0 +1,77 @@ +// 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_provideSiloedLiquidity is SiloedLockReleaseTokenPoolSetup { + address public UNAUTHORIZED_ADDRESS = address(0xdeadbeef); + + function setUp() public override { + super.setUp(); + + s_siloedLockReleaseTokenPool.setSiloRebalancer(SILOED_CHAIN_SELECTOR, OWNER); + } + + function test_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_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); + } + + // Reverts + + function test_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_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_RevertWhen_LiquidityAmountCannotBeZero() public { + vm.expectRevert(abi.encodeWithSelector(SiloedLockReleaseTokenPool.LiquidityAmountCannotBeZero.selector)); + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(SILOED_CHAIN_SELECTOR, 0); + } + + function test_RevertWhen_InvalidChainSelector_Zero() public { + vm.expectRevert(abi.encodeWithSelector(SiloedLockReleaseTokenPool.InvalidChainSelector.selector, 0)); + + s_siloedLockReleaseTokenPool.provideSiloedLiquidity(0, 1); + } +} 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 index ea676d53015..661381038ae 100644 --- 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 @@ -9,7 +9,7 @@ contract SiloedLockReleaseTokenPool_setRebalancer is SiloedLockReleaseTokenPoolS function test_setSiloRebalancer() public { vm.expectEmit(); - emit SiloedLockReleaseTokenPool.SiloRebalancerSet(SILOED_CHAIN_SELECTOR, REBALANCER_ADDRESS, OWNER); + emit SiloedLockReleaseTokenPool.SiloRebalancerSet(SILOED_CHAIN_SELECTOR, OWNER, REBALANCER_ADDRESS); s_siloedLockReleaseTokenPool.setSiloRebalancer(SILOED_CHAIN_SELECTOR, REBALANCER_ADDRESS); @@ -19,11 +19,12 @@ contract SiloedLockReleaseTokenPool_setRebalancer is SiloedLockReleaseTokenPoolS function test_setRebalancer_UnsiloedChains() public { vm.expectEmit(); - emit SiloedLockReleaseTokenPool.UnsiloedRebalancerSet(REBALANCER_ADDRESS, OWNER); + emit SiloedLockReleaseTokenPool.UnsiloedRebalancerSet(OWNER, REBALANCER_ADDRESS); s_siloedLockReleaseTokenPool.setRebalancer(REBALANCER_ADDRESS); assertEq(s_siloedLockReleaseTokenPool.getSiloRebalancer(DEST_CHAIN_SELECTOR), REBALANCER_ADDRESS); + assertEq(s_siloedLockReleaseTokenPool.getRebalancer(), REBALANCER_ADDRESS); } // Reverts 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 index 506b1373ceb..38fdff34871 100644 --- 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 @@ -8,24 +8,7 @@ contract SiloedLockReleaseTokenPool_updateSiloDesignations is SiloedLockReleaseT 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); @@ -47,6 +30,27 @@ contract SiloedLockReleaseTokenPool_updateSiloDesignations is SiloedLockReleaseT // Assert that the available liquidity moved from being siloed to unsiloed. assertEq(s_siloedLockReleaseTokenPool.getUnsiloedLiquidity(), amount); + + // Now we re-silo the chain + 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.provideSiloedLiquidity(SILOED_CHAIN_SELECTOR, amount); + assertEq(s_siloedLockReleaseTokenPool.getAvailableTokens(SILOED_CHAIN_SELECTOR), amount); } // Reverts @@ -62,12 +66,26 @@ contract SiloedLockReleaseTokenPool_updateSiloDesignations is SiloedLockReleaseT ); } - function test_updateSiloDesignations_RevertWhen_InvalidChainSelector() public { + function test_updateSiloDesignations_RevertWhen_InvalidChainSelector_ChainSelectorZero() public { SiloedLockReleaseTokenPool.SiloConfigUpdate[] memory adds = new SiloedLockReleaseTokenPool.SiloConfigUpdate[](1); adds[0] = SiloedLockReleaseTokenPool.SiloConfigUpdate({remoteChainSelector: 0, rebalancer: OWNER}); + // Chain selector cannot be zero vm.expectRevert(abi.encodeWithSelector(SiloedLockReleaseTokenPool.InvalidChainSelector.selector, 0)); s_siloedLockReleaseTokenPool.updateSiloDesignations(new uint64[](0), adds); } + + function test_updateSiloDesignations_RevertWhen_InvalidChainSelector_ChainAlreadySiloed() public { + SiloedLockReleaseTokenPool.SiloConfigUpdate[] memory adds = new SiloedLockReleaseTokenPool.SiloConfigUpdate[](1); + adds[0] = + SiloedLockReleaseTokenPool.SiloConfigUpdate({remoteChainSelector: SILOED_CHAIN_SELECTOR, rebalancer: OWNER}); + + // Since the chain is already siloed you cannot re-silo it. + vm.expectRevert( + abi.encodeWithSelector(SiloedLockReleaseTokenPool.InvalidChainSelector.selector, SILOED_CHAIN_SELECTOR) + ); + + 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 index 7a82f0954a0..ab9c58b2a38 100644 --- 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 @@ -123,4 +123,10 @@ contract SiloedLockReleaseTokenPool_withdrawLiqudity is SiloedLockReleaseTokenPo s_siloedLockReleaseTokenPool.withdrawLiquidity(1); } + + function test_withdrawLiquidity_RevertWhen_LiquidityAmountCannotBeZero() public { + vm.expectRevert(SiloedLockReleaseTokenPool.LiquidityAmountCannotBeZero.selector); + + s_siloedLockReleaseTokenPool.withdrawLiquidity(0); + } } diff --git a/core/gethwrappers/ccip/generated/burn_to_address_mint_token_pool/burn_to_address_mint_token_pool.go b/core/gethwrappers/ccip/generated/burn_to_address_mint_token_pool/burn_to_address_mint_token_pool.go new file mode 100644 index 00000000000..21fe8a26520 --- /dev/null +++ b/core/gethwrappers/ccip/generated/burn_to_address_mint_token_pool/burn_to_address_mint_token_pool.go @@ -0,0 +1,3209 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package burn_to_address_mint_token_pool + +import ( + "errors" + "fmt" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +type PoolLockOrBurnInV1 struct { + Receiver []byte + RemoteChainSelector uint64 + OriginalSender common.Address + Amount *big.Int + LocalToken common.Address +} + +type PoolLockOrBurnOutV1 struct { + DestTokenAddress []byte + DestPoolData []byte +} + +type PoolReleaseOrMintInV1 struct { + OriginalSender []byte + RemoteChainSelector uint64 + Receiver common.Address + Amount *big.Int + LocalToken common.Address + SourcePoolAddress []byte + SourcePoolData []byte + OffchainTokenData []byte +} + +type PoolReleaseOrMintOutV1 struct { + DestinationAmount *big.Int +} + +type RateLimiterConfig struct { + IsEnabled bool + Capacity *big.Int + Rate *big.Int +} + +type RateLimiterTokenBucket struct { + Tokens *big.Int + LastUpdated uint32 + IsEnabled bool + Capacity *big.Int + Rate *big.Int +} + +type TokenPoolChainUpdate struct { + RemoteChainSelector uint64 + RemotePoolAddresses [][]byte + RemoteTokenAddress []byte + OutboundRateLimiterConfig RateLimiterConfig + InboundRateLimiterConfig RateLimiterConfig +} + +var BurnToAddressMintTokenPoolMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIBurnMintERC20\"},{\"name\":\"localTokenDecimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"allowlist\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"rmnProxy\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"router\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burnAddress\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"acceptOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addRemotePool\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"applyAllowListUpdates\",\"inputs\":[{\"name\":\"removes\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"adds\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"applyChainUpdates\",\"inputs\":[{\"name\":\"remoteChainSelectorsToRemove\",\"type\":\"uint64[]\",\"internalType\":\"uint64[]\"},{\"name\":\"chainsToAdd\",\"type\":\"tuple[]\",\"internalType\":\"structTokenPool.ChainUpdate[]\",\"components\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddresses\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"remoteTokenAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getAllowList\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllowListEnabled\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getBurnAddress\",\"inputs\":[],\"outputs\":[{\"name\":\"burnAddress\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentInboundRateLimiterState\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.TokenBucket\",\"components\":[{\"name\":\"tokens\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"lastUpdated\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentOutboundRateLimiterState\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.TokenBucket\",\"components\":[{\"name\":\"tokens\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"lastUpdated\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRateLimitAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRemotePools\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRemoteToken\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRmnProxy\",\"inputs\":[],\"outputs\":[{\"name\":\"rmnProxy\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRouter\",\"inputs\":[],\"outputs\":[{\"name\":\"router\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSupportedChains\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64[]\",\"internalType\":\"uint64[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getToken\",\"inputs\":[],\"outputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getTokenDecimals\",\"inputs\":[],\"outputs\":[{\"name\":\"decimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"i_burnAddress\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRemotePool\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSupportedChain\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSupportedToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"lockOrBurn\",\"inputs\":[{\"name\":\"lockOrBurnIn\",\"type\":\"tuple\",\"internalType\":\"structPool.LockOrBurnInV1\",\"components\":[{\"name\":\"receiver\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"originalSender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"localToken\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structPool.LockOrBurnOutV1\",\"components\":[{\"name\":\"destTokenAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"destPoolData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"releaseOrMint\",\"inputs\":[{\"name\":\"releaseOrMintIn\",\"type\":\"tuple\",\"internalType\":\"structPool.ReleaseOrMintInV1\",\"components\":[{\"name\":\"originalSender\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"localToken\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"sourcePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"sourcePoolData\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"offchainTokenData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"components\":[{\"name\":\"destinationAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeRemotePool\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setChainRateLimiterConfig\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"outboundConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setChainRateLimiterConfigs\",\"inputs\":[{\"name\":\"remoteChainSelectors\",\"type\":\"uint64[]\",\"internalType\":\"uint64[]\"},{\"name\":\"outboundConfigs\",\"type\":\"tuple[]\",\"internalType\":\"structRateLimiter.Config[]\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundConfigs\",\"type\":\"tuple[]\",\"internalType\":\"structRateLimiter.Config[]\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRateLimitAdmin\",\"inputs\":[{\"name\":\"rateLimitAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRouter\",\"inputs\":[{\"name\":\"newRouter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"typeAndVersion\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"AllowListAdd\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AllowListRemove\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Burned\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChainAdded\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"remoteToken\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChainConfigured\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChainRemoved\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ConfigChanged\",\"inputs\":[{\"name\":\"config\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Locked\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Minted\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferRequested\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RateLimitAdminSet\",\"inputs\":[{\"name\":\"rateLimitAdmin\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Released\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RemotePoolAdded\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RemotePoolRemoved\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RouterUpdated\",\"inputs\":[{\"name\":\"oldRouter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newRouter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokensConsumed\",\"inputs\":[{\"name\":\"tokens\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AggregateValueMaxCapacityExceeded\",\"inputs\":[{\"name\":\"capacity\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"requested\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"AggregateValueRateLimitReached\",\"inputs\":[{\"name\":\"minWaitInSeconds\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"available\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"AllowListNotEnabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BucketOverfilled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CallerIsNotARampOnRouter\",\"inputs\":[{\"name\":\"caller\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"CannotTransferToSelf\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ChainAlreadyExists\",\"inputs\":[{\"name\":\"chainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"ChainNotAllowed\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"CursedByRMN\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DisabledNonZeroRateLimit\",\"inputs\":[{\"name\":\"config\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}]},{\"type\":\"error\",\"name\":\"InvalidDecimalArgs\",\"inputs\":[{\"name\":\"expected\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"actual\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"type\":\"error\",\"name\":\"InvalidRateLimitRate\",\"inputs\":[{\"name\":\"rateLimiterConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}]},{\"type\":\"error\",\"name\":\"InvalidRemoteChainDecimals\",\"inputs\":[{\"name\":\"sourcePoolData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"InvalidRemotePoolForChain\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"InvalidSourcePoolAddress\",\"inputs\":[{\"name\":\"sourcePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"InvalidToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"MismatchedArrayLengths\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MustBeProposedOwner\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NonExistentChain\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"OnlyCallableByOwner\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OverflowDetected\",\"inputs\":[{\"name\":\"remoteDecimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"localDecimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"remoteAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"OwnerCannotBeZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"PoolAlreadyAdded\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"RateLimitMustBeDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SenderNotAllowed\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"TokenMaxCapacityExceeded\",\"inputs\":[{\"name\":\"capacity\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"requested\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"tokenAddress\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"TokenRateLimitReached\",\"inputs\":[{\"name\":\"minWaitInSeconds\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"available\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"tokenAddress\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[{\"name\":\"caller\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ZeroAddressNotAllowed\",\"inputs\":[]}]", + Bin: "0x610120806040523461038257614bdb803803809161001d8285610401565b8339810160c0828203126103825781516001600160a01b03811692908390036103825761004c60208201610424565b60408201516001600160401b0381116103825782019280601f85011215610382578351936001600160401b0385116103eb578460051b9060208201956100956040519788610401565b865260208087019282010192831161038257602001905b8282106103d3575050506100c260608301610432565b936100db60a06100d460808601610432565b9401610432565b9433156103c257600180546001600160a01b03191633179055811580156103b1575b80156103a0575b61038f578160209160049360805260c0526040519283809263313ce56760e01b82525afa6000918161034e575b50610323575b5060a052600480546001600160a01b0319166001600160a01b03929092169190911790558051151560e0819052610206575b50610100526040516145f490816105e7823960805181818161161701528181611809015281816123630152818161253f0152818161285101526128c9015260a05181818161196f015281816127d80152818161332d01526133b0015260c051818181610beb015281816116b301526123fe015260e051818181610b7b015281816116f6015261215a01526101005181818161185e0152612c420152f35b60206040516102158282610401565b60008152600036813760e051156103125760005b8151811015610290576001906001600160a01b036102478285610446565b51168461025382610488565b610260575b505001610229565b7f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf756691604051908152a13884610258565b505060005b8251811015610309576001906001600160a01b036102b38286610446565b5116801561030357836102c582610586565b6102d3575b50505b01610295565b7f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d891604051908152a138836102ca565b506102cd565b50505038610169565b6335f4a7b360e01b60005260046000fd5b60ff1660ff82168181036103375750610137565b6332ad3e0760e11b60005260045260245260446000fd5b9091506020813d602011610387575b8161036a60209383610401565b810103126103825761037b90610424565b9038610131565b600080fd5b3d915061035d565b6342bcdf7f60e11b60005260046000fd5b506001600160a01b03811615610104565b506001600160a01b038416156100fd565b639b15e16f60e01b60005260046000fd5b602080916103e084610432565b8152019101906100ac565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b038211908210176103eb57604052565b519060ff8216820361038257565b51906001600160a01b038216820361038257565b805182101561045a5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b805482101561045a5760005260206000200190600090565b600081815260036020526040902054801561057f5760001981018181116105695760025460001981019190821161056957818103610518575b505050600254801561050257600019016104dc816002610470565b8154906000199060031b1b19169055600255600052600360205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b61055161052961053a936002610470565b90549060031b1c9283926002610470565b819391549060031b91821b91600019901b19161790565b905560005260036020526040600020553880806104c1565b634e487b7160e01b600052601160045260246000fd5b5050600090565b806000526003602052604060002054156000146105e057600254680100000000000000008110156103eb576105c761053a8260018594016002556002610470565b9055600254906000526003602052604060002055600190565b5060009056fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461296c57508063181f5a77146128ed57806321df0da71461287e578063240028e8146127fc57806324f65ee7146127a057806338b39d2914610dde57806339077537146122bd5780634c5ef0ed146122a357806354c8a4f31461212657806362ddd3c4146120a25780636d3d1a581461205057806379ba509714611f6b5780637d54534e14611ebe5780638926f54f14611e5a5780638da5cb5b14611e08578063962d402014611c645780639a4575b91461156f578063a42a7b8b146113ea578063a7cd63b71461131e578063acfecf91146111fa578063af58d59f14611193578063b0f479a114611141578063b7946580146110ea578063c0d7865514610ff2578063c4bffe2b14610ea9578063c75eea9c14610de3578063c8de9fe014610dde578063cf7401f314610c0f578063dc0bd97114610ba0578063e0351e1314610b45578063e8a1da17146102705763f2fde38b1461018157600080fd5b3461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d5773ffffffffffffffffffffffffffffffffffffffff6101cd612bd4565b6101d56134ba565b1633811461024557807fffffffffffffffffffffffff000000000000000000000000000000000000000083541617825573ffffffffffffffffffffffffffffffffffffffff600154167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12788380a380f35b6004827fdad89dca000000000000000000000000000000000000000000000000000000008152fd5b80fd5b503461026d5761027f36612d31565b9391909261028b6134ba565b82915b8083106109b0575050508063ffffffff4216917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee1843603015b858210156109ac578160051b850135818112156109a857850190610120823603126109a857604051956102f987612ac2565b823567ffffffffffffffff811681036109a3578752602083013567ffffffffffffffff811161099f5783019536601f8801121561099f5786359661033c88612f2f565b9761034a604051998a612afa565b8089526020808a019160051b8301019036821161099b5760208301905b828210610968575050505060208801968752604084013567ffffffffffffffff81116109645761039a9036908601613287565b9860408901998a526103c46103b23660608801612def565b9560608b0196875260c0369101612def565b9660808a019788526103d68651613931565b6103e08851613931565b8a51511561093c576103fc67ffffffffffffffff8b5116614184565b156109055767ffffffffffffffff8a5116815260076020526040812061053c87516fffffffffffffffffffffffffffffffff604082015116906104f76fffffffffffffffffffffffffffffffff6020830151169151151583608060405161046281612ac2565b858152602081018c905260408101849052606081018690520152855474ff000000000000000000000000000000000000000091151560a01b919091167fffffffffffffffffffffff0000000000000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff84161773ffffffff0000000000000000000000000000000060808b901b1617178555565b60809190911b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff91909116176001830155565b61066289516fffffffffffffffffffffffffffffffff6040820151169061061d6fffffffffffffffffffffffffffffffff6020830151169151151583608060405161058681612ac2565b858152602081018c9052604081018490526060810186905201526002860180547fffffffffffffffffffffff000000000000000000000000000000000000000000166fffffffffffffffffffffffffffffffff85161773ffffffff0000000000000000000000000000000060808c901b161791151560a01b74ff000000000000000000000000000000000000000016919091179055565b60809190911b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff91909116176003830155565b60048c5191019080519067ffffffffffffffff82116108d8576106858354613027565b601f811161089d575b50602090601f83116001146107fe576106dc92918591836107f3575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b90555b805b89518051821015610717579061071160019261070a838f67ffffffffffffffff90511692613013565b5190613505565b016106e1565b5050975097987f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2929593966107e567ffffffffffffffff600197949c51169251935191516107b161077c60405196879687526101006020880152610100870190612b75565b9360408601906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b60a08401906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b0390a10190939492916102c7565b0151905038806106aa565b83855281852091907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08416865b818110610885575090846001959493921061084e575b505050811b0190556106df565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c19169055388080610841565b9293602060018192878601518155019501930161082b565b6108c89084865260208620601f850160051c810191602086106108ce575b601f0160051c019061322e565b3861068e565b90915081906108bb565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60249067ffffffffffffffff8b51167f1d5ad3c5000000000000000000000000000000000000000000000000000000008252600452fd5b807f8579befe0000000000000000000000000000000000000000000000000000000060049252fd5b8680fd5b813567ffffffffffffffff81116109975760209161098c8392833691890101613287565b815201910190610367565b8a80fd5b8880fd5b8580fd5b600080fd5b8380fd5b8280f35b9092919367ffffffffffffffff6109d06109cb878588612faf565b612fee565b16956109db87613eb8565b15610b195786845260076020526109f760056040862001613cbf565b94845b8651811015610a30576001908987526007602052610a2960056040892001610a22838b613013565b5190613fe3565b50016109fa565b5093945094909580855260076020526005604086208681558660018201558660028201558660038201558660048201610a698154613027565b80610ad8575b5050500180549086815581610aba575b5050907f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599166020600193604051908152a101919094939461028e565b865260208620908101905b81811015610a7f57868155600101610ac5565b601f8111600114610aee5750555b863880610a6f565b81835260208320610b0991601f01861c81019060010161322e565b8082528160208120915555610ae6565b602484887f1e670e4b000000000000000000000000000000000000000000000000000000008252600452fd5b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461026d5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57610c47612c66565b9060607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261026d57604051610c7e81612ade565b6024358015158103610dda5781526044356fffffffffffffffffffffffffffffffff81168103610dda5760208201526064356fffffffffffffffffffffffffffffffff81168103610dda57604082015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c360112610dd65760405190610d0582612ade565b60843580151581036109a857825260a4356fffffffffffffffffffffffffffffffff811681036109a857602083015260c4356fffffffffffffffffffffffffffffffff811681036109a857604083015273ffffffffffffffffffffffffffffffffffffffff6009541633141580610db4575b610d8857610d85929361376f565b80f35b6024837f8e4a23d600000000000000000000000000000000000000000000000000000000815233600452fd5b5073ffffffffffffffffffffffffffffffffffffffff60015416331415610d77565b5080fd5b8280fd5b612bf7565b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57610e4c610e476040610ea59367ffffffffffffffff610e30612c66565b610e3861317b565b501681526007602052206131a6565b6138ac565b6040519182918291909160806fffffffffffffffffffffffffffffffff8160a084019582815116855263ffffffff6020820151166020860152604081015115156040860152826060820151166060860152015116910152565b0390f35b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57604051906005548083528260208101600584526020842092845b818110610fd9575050610f0792500383612afa565b8151610f2b610f1582612f2f565b91610f236040519384612afa565b808352612f2f565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0602083019301368437805b8451811015610f8a578067ffffffffffffffff610f7760019388613013565b5116610f838286613013565b5201610f58565b50925090604051928392602084019060208552518091526040840192915b818110610fb6575050500390f35b825167ffffffffffffffff16845285945060209384019390920191600101610fa8565b8454835260019485019487945060209093019201610ef2565b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d5773ffffffffffffffffffffffffffffffffffffffff61103f612bd4565b6110476134ba565b1680156110c25760407f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f16849160045490807fffffffffffffffffffffffff000000000000000000000000000000000000000083161760045573ffffffffffffffffffffffffffffffffffffffff8351921682526020820152a180f35b6004827f8579befe000000000000000000000000000000000000000000000000000000008152fd5b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57610ea561112d611128612c66565b61320c565b604051918291602083526020830190612b75565b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57602073ffffffffffffffffffffffffffffffffffffffff60045416604051908152f35b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57610e4c610e4760026040610ea59467ffffffffffffffff6111e2612c66565b6111ea61317b565b50168152600760205220016131a6565b503461026d5767ffffffffffffffff61121236612c7d565b92909161121d6134ba565b1691611236836000526006602052604060002054151590565b156112f257828452600760205261126560056040862001611258368486612e8c565b6020815191012090613fe3565b156112aa57907f52d00ee4d9bd51b40168f2afc5848837288ce258784ad914278791464b3f4d76916112a460405192839260208452602084019161313c565b0390a280f35b826112ee836040519384937f74f23c7c000000000000000000000000000000000000000000000000000000008552600485015260406024850152604484019161313c565b0390fd5b602484847f1e670e4b000000000000000000000000000000000000000000000000000000008252600452fd5b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57604051600254808252602082018091600285526020852090855b8181106113d4575050508261137d910383612afa565b604051928392602084019060208552518091526040840192915b8181106113a5575050500390f35b825173ffffffffffffffffffffffffffffffffffffffff16845285945060209384019390920191600101611397565b8254845260209093019260019283019201611367565b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d5767ffffffffffffffff61142b612c66565b168152600760205261144260056040832001613cbf565b80517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061148761147183612f2f565b9261147f6040519485612afa565b808452612f2f565b01835b81811061155e575050825b82518110156114db57806114ab60019285613013565b51855260086020526114bf6040862061307a565b6114c98285613013565b526114d48184613013565b5001611495565b81846040519182916020830160208452825180915260408401602060408360051b870101940192905b82821061151357505050500390f35b9193602061154e827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc060019597998495030186528851612b75565b9601920192018594939192611504565b80606060208093860101520161148a565b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d5760043567ffffffffffffffff8111610dd65760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610dd657606060206040516115ed81612aa6565b8281520152608481016115ff81612ec3565b73ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000000000000000000000000000000000000000000016911603611c1a5750602481019077ffffffffffffffff0000000000000000000000000000000061166683612fee565b60801b16604051907f2cbc26bb000000000000000000000000000000000000000000000000000000008252600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115611b3b578491611beb575b50611bc3576116f460448201612ec3565b7f0000000000000000000000000000000000000000000000000000000000000000611b71575b5067ffffffffffffffff61172d83612fee565b16611745816000526006602052604060002054151590565b15611b4657602073ffffffffffffffffffffffffffffffffffffffff60045416916024604051809481937fa8d87a3b00000000000000000000000000000000000000000000000000000000835260048301525afa8015611b3b578490611ad8575b73ffffffffffffffffffffffffffffffffffffffff9150163303611aac57611920829360646117dd67ffffffffffffffff95612fee565b93013593849316815260076020526118316040822073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016958691614233565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082019081527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16602483015260448083018690528252949091906118b1606484612afa565b81806040978851956118c38a88612afa565b602087527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020880152519082855af1903d15611aa3573d61190481612b3b565b9061191189519283612afa565b8152809360203d92013e61451b565b805180611a02575b6119d184610ea5611967611128898885519081527f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df760203392a2612fee565b9180519060ff7f0000000000000000000000000000000000000000000000000000000000000000166020830152602082526119a28183612afa565b8051936119ae85612aa6565b845260208401918252805194859460208652518260208701526060860190612b75565b9151907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08584030190850152612b75565b90602080611a149383010191016132a2565b15611a20573880611928565b608482517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b6060925061451b565b6024837f728fe07b00000000000000000000000000000000000000000000000000000000815233600452fd5b506020813d602011611b33575b81611af260209383612afa565b810103126109a8575173ffffffffffffffffffffffffffffffffffffffff811681036109a85773ffffffffffffffffffffffffffffffffffffffff906117a6565b3d9150611ae5565b6040513d86823e3d90fd5b7fa9902c7e000000000000000000000000000000000000000000000000000000008452600452602483fd5b73ffffffffffffffffffffffffffffffffffffffff168084526003602052604084205461171a577fd0d25976000000000000000000000000000000000000000000000000000000008452600452602483fd5b6004837f53ad11d8000000000000000000000000000000000000000000000000000000008152fd5b611c0d915060203d602011611c13575b611c058183612afa565b8101906132a2565b386116e3565b503d611bfb565b8273ffffffffffffffffffffffffffffffffffffffff611c3b602493612ec3565b7f961c9a4f00000000000000000000000000000000000000000000000000000000835216600452fd5b503461026d5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d5760043567ffffffffffffffff8111610dd657611cb4903690600401612d00565b60243567ffffffffffffffff81116109a857611cd4903690600401612da1565b60449291923567ffffffffffffffff811161099f57611cf7903690600401612da1565b91909273ffffffffffffffffffffffffffffffffffffffff6009541633141580611de6575b611dba57818114801590611db0575b611d8857865b818110611d3c578780f35b80611d82611d506109cb600194868c612faf565b611d5b83878b613003565b611d7c611d74611d6c868b8d613003565b923690612def565b913690612def565b9161376f565b01611d31565b6004877f568efce2000000000000000000000000000000000000000000000000000000008152fd5b5082811415611d2b565b6024877f8e4a23d600000000000000000000000000000000000000000000000000000000815233600452fd5b5073ffffffffffffffffffffffffffffffffffffffff60015416331415611d1c565b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d576020611eb467ffffffffffffffff611ea0612c66565b166000526006602052604060002054151590565b6040519015158152f35b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d577f44676b5284b809a22248eba0da87391d79098be38bb03154be88a58bf4d09174602073ffffffffffffffffffffffffffffffffffffffff611f2e612bd4565b611f366134ba565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000006009541617600955604051908152a180f35b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57805473ffffffffffffffffffffffffffffffffffffffff81163303612028577fffffffffffffffffffffffff000000000000000000000000000000000000000060015491338284161760015516825573ffffffffffffffffffffffffffffffffffffffff3391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6004827f02b543c6000000000000000000000000000000000000000000000000000000008152fd5b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57602073ffffffffffffffffffffffffffffffffffffffff60095416604051908152f35b503461026d576120b136612c7d565b6120bd939291936134ba565b67ffffffffffffffff82166120df816000526006602052604060002054151590565b156120fb5750610d8592936120f5913691612e8c565b90613505565b7f1e670e4b000000000000000000000000000000000000000000000000000000008452600452602483fd5b503461026d576121509061215861213c36612d31565b95916121499391936134ba565b3691612f47565b933691612f47565b7f00000000000000000000000000000000000000000000000000000000000000001561227b57815b83518110156121f3578073ffffffffffffffffffffffffffffffffffffffff6121ab60019387613013565b51166121b681613d22565b6121c2575b5001612180565b60207f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf756691604051908152a1386121bb565b5090805b8251811015612277578073ffffffffffffffffffffffffffffffffffffffff61222260019386613013565b511680156122715761223381614124565b612240575b505b016121f7565b60207f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d891604051908152a184612238565b5061223a565b5080f35b6004827f35f4a7b3000000000000000000000000000000000000000000000000000000008152fd5b503461026d576020611eb46122b736612c7d565b91612ee4565b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d5760043567ffffffffffffffff8111610dd657806004016101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8336030112610dda578260405161233d81612a5b565b526084820161234b81612ec3565b73ffffffffffffffffffffffffffffffffffffffff807f00000000000000000000000000000000000000000000000000000000000000001691160361277f57506024820177ffffffffffffffff000000000000000000000000000000006123b182612fee565b60801b16604051907f2cbc26bb000000000000000000000000000000000000000000000000000000008252600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115612702578591612760575b506127385767ffffffffffffffff61244582612fee565b1661245d816000526006602052604060002054151590565b1561270d57602073ffffffffffffffffffffffffffffffffffffffff60045416916044604051809481937f83826b2b00000000000000000000000000000000000000000000000000000000835260048301523360248301525afa9081156127025785916126e3575b50156126b7576124d481612fee565b6124e660a48501916122b78386612e3b565b15612670575061258367ffffffffffffffff9261257d61257861257161250d604496612fee565b936064890135978895168a526007602052612567600260408c200173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016998a91614233565b60c4890190612e3b565b3691612e8c565b6132ba565b906133ad565b9201908361259083612ec3565b823b15610dd6576040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91909116600482015260248101859052918290604490829084905af18015611b3b579160209461261e9273ffffffffffffffffffffffffffffffffffffffff94612660575b5050612ec3565b166040518281527f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0843392a38060405161265781612a5b565b52604051908152f35b8161266a91612afa565b38612617565b61267a9083612e3b565b6112ee6040519283927f24eb47e500000000000000000000000000000000000000000000000000000000845260206004850152602484019161313c565b6024847f728fe07b00000000000000000000000000000000000000000000000000000000815233600452fd5b6126fc915060203d602011611c1357611c058183612afa565b386124c5565b6040513d87823e3d90fd5b7fa9902c7e000000000000000000000000000000000000000000000000000000008552600452602484fd5b6004847f53ad11d8000000000000000000000000000000000000000000000000000000008152fd5b612779915060203d602011611c1357611c058183612afa565b3861242e565b8373ffffffffffffffffffffffffffffffffffffffff611c3b602493612ec3565b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461026d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57602090612837612bd4565b905073ffffffffffffffffffffffffffffffffffffffff807f0000000000000000000000000000000000000000000000000000000000000000169116146040519015158152f35b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461026d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026d5750610ea560405161292e604082612afa565b601c81527f4275726e546f41646472657373546f6b656e506f6f6c20312e352e31000000006020820152604051918291602083526020830190612b75565b905034610dd65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610dd6576004357fffffffff000000000000000000000000000000000000000000000000000000008116809103610dda57602092507faff2afbf000000000000000000000000000000000000000000000000000000008114908115612a31575b8115612a07575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612a00565b7f0e64dd2900000000000000000000000000000000000000000000000000000000811491506129f9565b6020810190811067ffffffffffffffff821117612a7757604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff821117612a7757604052565b60a0810190811067ffffffffffffffff821117612a7757604052565b6060810190811067ffffffffffffffff821117612a7757604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612a7757604052565b67ffffffffffffffff8111612a7757601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b919082519283825260005b848110612bbf5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b80602080928401015182828601015201612b80565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036109a357565b346109a35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126109a357602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b6004359067ffffffffffffffff821682036109a357565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126109a35760043567ffffffffffffffff811681036109a3579160243567ffffffffffffffff81116109a357826023820112156109a35780600401359267ffffffffffffffff84116109a357602484830101116109a3576024019190565b9181601f840112156109a35782359167ffffffffffffffff83116109a3576020808501948460051b0101116109a357565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126109a35760043567ffffffffffffffff81116109a35781612d7a91600401612d00565b929092916024359067ffffffffffffffff82116109a357612d9d91600401612d00565b9091565b9181601f840112156109a35782359167ffffffffffffffff83116109a357602080850194606085020101116109a357565b35906fffffffffffffffffffffffffffffffff821682036109a357565b91908260609103126109a357604051612e0781612ade565b809280359081151582036109a3576040612e369181938552612e2b60208201612dd2565b602086015201612dd2565b910152565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156109a3570180359067ffffffffffffffff82116109a3576020019181360383136109a357565b929192612e9882612b3b565b91612ea66040519384612afa565b8294818452818301116109a3578281602093846000960137010152565b3573ffffffffffffffffffffffffffffffffffffffff811681036109a35790565b612f2c929167ffffffffffffffff612f0f921660005260076020526005604060002001923691612e8c565b602081519101209060019160005201602052604060002054151590565b90565b67ffffffffffffffff8111612a775760051b60200190565b9291612f5282612f2f565b93612f606040519586612afa565b602085848152019260051b81019182116109a357915b818310612f8257505050565b823573ffffffffffffffffffffffffffffffffffffffff811681036109a357815260209283019201612f76565b9190811015612fbf5760051b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b3567ffffffffffffffff811681036109a35790565b9190811015612fbf576060020190565b8051821015612fbf5760209160051b010190565b90600182811c92168015613070575b602083101461304157565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691613036565b906040519182600082549261308e84613027565b80845293600181169081156130fc57506001146130b5575b506130b392500383612afa565b565b90506000929192526020600020906000915b8183106130e05750509060206130b392820101386130a6565b60209193508060019154838589010152019101909184926130c7565b602093506130b39592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b820101386130a6565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b6040519061318882612ac2565b60006080838281528260208201528260408201528260608201520152565b906040516131b381612ac2565b60806001829460ff81546fffffffffffffffffffffffffffffffff8116865263ffffffff81861c16602087015260a01c161515604085015201546fffffffffffffffffffffffffffffffff81166060840152811c910152565b67ffffffffffffffff166000526007602052612f2c600460406000200161307a565b818110613239575050565b6000815560010161322e565b8181029291811591840414171561325857565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9080601f830112156109a357816020612f2c93359101612e8c565b908160209103126109a3575180151581036109a35790565b80518015613329576020036132eb576020818051810103126109a35760208101519060ff82116132eb575060ff1690565b6112ee906040519182917f953576f7000000000000000000000000000000000000000000000000000000008352602060048401526024830190612b75565b50507f000000000000000000000000000000000000000000000000000000000000000090565b9060ff8091169116039060ff821161325857565b60ff16604d811161325857600a0a90565b811561337e570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b907f00000000000000000000000000000000000000000000000000000000000000009060ff82169060ff8116928284146134b35782841161348957906133f29161334f565b91604d60ff8416118015613450575b61341a57505090613414612f2c92613363565b90613245565b9091507fa9cb113d0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b5061345a83613363565b801561337e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048411613401565b6134929161334f565b91604d60ff84161161341a575050906134ad612f2c92613363565b90613374565b5050505090565b73ffffffffffffffffffffffffffffffffffffffff6001541633036134db57565b7f2b5c74de0000000000000000000000000000000000000000000000000000000060005260046000fd5b908051156137455767ffffffffffffffff8151602083012092169182600052600760205261353a8160056040600020016141de565b156137015760005260086020526040600020815167ffffffffffffffff8111612a77576135678254613027565b601f81116136cf575b506020601f821160011461360957916135e3827f7d628c9a1796743d365ab521a8b2a4686e419b3269919dc9145ea2ce853b54ea95936135f9956000916135fe575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b9055604051918291602083526020830190612b75565b0390a2565b9050840151386135b2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169083600052806000209160005b8181106136b75750926135f99492600192827f7d628c9a1796743d365ab521a8b2a4686e419b3269919dc9145ea2ce853b54ea989610613680575b5050811b01905561112d565b8501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880613674565b9192602060018192868a015181550194019201613639565b6136fb90836000526020600020601f840160051c810191602085106108ce57601f0160051c019061322e565b38613570565b50906112ee6040519283927f393b8ad20000000000000000000000000000000000000000000000000000000084526004840152604060248401526044830190612b75565b7f8579befe0000000000000000000000000000000000000000000000000000000060005260046000fd5b67ffffffffffffffff166000818152600660205260409020549092919015613871579161386e60e09261383a856137c67f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b97613931565b8460005260076020526137dd816040600020613a8c565b6137e683613931565b846000526007602052613800836002604060002001613a8c565b60405194855260208501906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b60808301906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565ba1565b827f1e670e4b0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b9190820391821161325857565b6138b461317b565b506fffffffffffffffffffffffffffffffff6060820151166fffffffffffffffffffffffffffffffff8083511691613911602085019361390b6138fe63ffffffff8751164261389f565b8560808901511690613245565b90614117565b8082101561392a57505b16825263ffffffff4216905290565b905061391b565b8051156139e5576fffffffffffffffffffffffffffffffff6040820151166fffffffffffffffffffffffffffffffff6020830151168110908115916139dc575b506139795750565b6064906139da604051917f8020d12400000000000000000000000000000000000000000000000000000000835260048301906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565bfd5b90501538613971565b6fffffffffffffffffffffffffffffffff60408201511615801590613a6d575b613a0c5750565b6064906139da604051917fd68af9cc00000000000000000000000000000000000000000000000000000000835260048301906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b506fffffffffffffffffffffffffffffffff6020820151161515613a05565b7f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1991613bc56060928054613ac963ffffffff8260801c164261389f565b9081613c04575b50506fffffffffffffffffffffffffffffffff6001816020860151169282815416808510600014613bfc57508280855b16167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416178155613b798651151582907fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff0000000000000000000000000000000000000000835492151560a01b169116179055565b60408601517fffffffffffffffffffffffffffffffff0000000000000000000000000000000060809190911b16939092166fffffffffffffffffffffffffffffffff1692909217910155565b61386e60405180926fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b838091613b00565b6fffffffffffffffffffffffffffffffff91613c39839283613c326001880154948286169560801c90613245565b9116614117565b80821015613cb857505b83547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff9290911692909216167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116174260801b73ffffffff00000000000000000000000000000000161781553880613ad0565b9050613c43565b906040519182815491828252602082019060005260206000209260005b818110613cf15750506130b392500383612afa565b8454835260019485019487945060209093019201613cdc565b8054821015612fbf5760005260206000200190600090565b6000818152600360205260409020548015613eb1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811161325857600254907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161325857818103613e42575b5050506002548015613e13577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01613dd0816002613d0a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055600255600052600360205260006040812055600190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b613e99613e53613e64936002613d0a565b90549060031b1c9283926002613d0a565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b90556000526003602052604060002055388080613d97565b5050600090565b6000818152600660205260409020548015613eb1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811161325857600554907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161325857818103613fa9575b5050506005548015613e13577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01613f66816005613d0a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055600555600052600660205260006040812055600190565b613fcb613fba613e64936005613d0a565b90549060031b1c9283926005613d0a565b90556000526006602052604060002055388080613f2d565b906001820191816000528260205260406000205480151560001461410e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818111613258578254907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211613258578181036140d7575b50505080548015613e13577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01906140988282613d0a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b191690555560005260205260006040812055600190565b6140f76140e7613e649386613d0a565b90549060031b1c92839286613d0a565b905560005283602052604060002055388080614060565b50505050600090565b9190820180921161325857565b8060005260036020526040600020541560001461417e5760025468010000000000000000811015612a7757614165613e648260018594016002556002613d0a565b9055600254906000526003602052604060002055600190565b50600090565b8060005260066020526040600020541560001461417e5760055468010000000000000000811015612a77576141c5613e648260018594016005556005613d0a565b9055600554906000526006602052604060002055600190565b6000828152600182016020526040902054613eb15780549068010000000000000000821015612a77578261421c613e64846001809601855584613d0a565b905580549260005201602052604060002055600190565b929192805460ff8160a01c16158015614513575b61450c576fffffffffffffffffffffffffffffffff8116906001830190815461428c63ffffffff6fffffffffffffffffffffffffffffffff83169360801c164261389f565b908161446e575b50508481106143ec575083821061431b57507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a939450906fffffffffffffffffffffffffffffffff806142e9856020969561389f565b16167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055604051908152a1565b81945061432d92505460801c9261389f565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908082116132585761437b6143809273ffffffffffffffffffffffffffffffffffffffff94614117565b613374565b92169182156143bc577fd0c8d23a0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b7f15279c080000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b8473ffffffffffffffffffffffffffffffffffffffff881691821561443e577f1a76572a0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b7ff94ebcd10000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b8285929395116144e2576144899261390b9160801c90613245565b808310156144dd5750815b83547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff164260801b73ffffffff0000000000000000000000000000000016178455913880614293565b614494565b7f9725942a0000000000000000000000000000000000000000000000000000000060005260046000fd5b5050509050565b508215614247565b91929015614596575081511561452f575090565b3b156145385790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156145a95750805190602001fd5b6112ee906040519182917f08c379a0000000000000000000000000000000000000000000000000000000008352602060048401526024830190612b7556fea164736f6c634300081a000a", +} + +var BurnToAddressMintTokenPoolABI = BurnToAddressMintTokenPoolMetaData.ABI + +var BurnToAddressMintTokenPoolBin = BurnToAddressMintTokenPoolMetaData.Bin + +func DeployBurnToAddressMintTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, localTokenDecimals uint8, allowlist []common.Address, rmnProxy common.Address, router common.Address, burnAddress common.Address) (common.Address, *types.Transaction, *BurnToAddressMintTokenPool, error) { + parsed, err := BurnToAddressMintTokenPoolMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BurnToAddressMintTokenPoolBin), backend, token, localTokenDecimals, allowlist, rmnProxy, router, burnAddress) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &BurnToAddressMintTokenPool{address: address, abi: *parsed, BurnToAddressMintTokenPoolCaller: BurnToAddressMintTokenPoolCaller{contract: contract}, BurnToAddressMintTokenPoolTransactor: BurnToAddressMintTokenPoolTransactor{contract: contract}, BurnToAddressMintTokenPoolFilterer: BurnToAddressMintTokenPoolFilterer{contract: contract}}, nil +} + +type BurnToAddressMintTokenPool struct { + address common.Address + abi abi.ABI + BurnToAddressMintTokenPoolCaller + BurnToAddressMintTokenPoolTransactor + BurnToAddressMintTokenPoolFilterer +} + +type BurnToAddressMintTokenPoolCaller struct { + contract *bind.BoundContract +} + +type BurnToAddressMintTokenPoolTransactor struct { + contract *bind.BoundContract +} + +type BurnToAddressMintTokenPoolFilterer struct { + contract *bind.BoundContract +} + +type BurnToAddressMintTokenPoolSession struct { + Contract *BurnToAddressMintTokenPool + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type BurnToAddressMintTokenPoolCallerSession struct { + Contract *BurnToAddressMintTokenPoolCaller + CallOpts bind.CallOpts +} + +type BurnToAddressMintTokenPoolTransactorSession struct { + Contract *BurnToAddressMintTokenPoolTransactor + TransactOpts bind.TransactOpts +} + +type BurnToAddressMintTokenPoolRaw struct { + Contract *BurnToAddressMintTokenPool +} + +type BurnToAddressMintTokenPoolCallerRaw struct { + Contract *BurnToAddressMintTokenPoolCaller +} + +type BurnToAddressMintTokenPoolTransactorRaw struct { + Contract *BurnToAddressMintTokenPoolTransactor +} + +func NewBurnToAddressMintTokenPool(address common.Address, backend bind.ContractBackend) (*BurnToAddressMintTokenPool, error) { + abi, err := abi.JSON(strings.NewReader(BurnToAddressMintTokenPoolABI)) + if err != nil { + return nil, err + } + contract, err := bindBurnToAddressMintTokenPool(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPool{address: address, abi: abi, BurnToAddressMintTokenPoolCaller: BurnToAddressMintTokenPoolCaller{contract: contract}, BurnToAddressMintTokenPoolTransactor: BurnToAddressMintTokenPoolTransactor{contract: contract}, BurnToAddressMintTokenPoolFilterer: BurnToAddressMintTokenPoolFilterer{contract: contract}}, nil +} + +func NewBurnToAddressMintTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*BurnToAddressMintTokenPoolCaller, error) { + contract, err := bindBurnToAddressMintTokenPool(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolCaller{contract: contract}, nil +} + +func NewBurnToAddressMintTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*BurnToAddressMintTokenPoolTransactor, error) { + contract, err := bindBurnToAddressMintTokenPool(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolTransactor{contract: contract}, nil +} + +func NewBurnToAddressMintTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*BurnToAddressMintTokenPoolFilterer, error) { + contract, err := bindBurnToAddressMintTokenPool(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolFilterer{contract: contract}, nil +} + +func bindBurnToAddressMintTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := BurnToAddressMintTokenPoolMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BurnToAddressMintTokenPool.Contract.BurnToAddressMintTokenPoolCaller.contract.Call(opts, result, method, params...) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.BurnToAddressMintTokenPoolTransactor.contract.Transfer(opts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.BurnToAddressMintTokenPoolTransactor.contract.Transact(opts, method, params...) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BurnToAddressMintTokenPool.Contract.contract.Call(opts, result, method, params...) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.contract.Transfer(opts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.contract.Transact(opts, method, params...) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getAllowList") + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetAllowList() ([]common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetAllowList(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetAllowList() ([]common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetAllowList(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getAllowListEnabled") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetAllowListEnabled() (bool, error) { + return _BurnToAddressMintTokenPool.Contract.GetAllowListEnabled(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetAllowListEnabled() (bool, error) { + return _BurnToAddressMintTokenPool.Contract.GetAllowListEnabled(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetBurnAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getBurnAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetBurnAddress() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetBurnAddress(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetBurnAddress() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetBurnAddress(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector) + + if err != nil { + return *new(RateLimiterTokenBucket), err + } + + out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + return _BurnToAddressMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + return _BurnToAddressMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector) + + if err != nil { + return *new(RateLimiterTokenBucket), err + } + + out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + return _BurnToAddressMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + return _BurnToAddressMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getRateLimitAdmin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetRateLimitAdmin() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetRateLimitAdmin(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetRateLimitAdmin() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetRateLimitAdmin(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetRemotePools(opts *bind.CallOpts, remoteChainSelector uint64) ([][]byte, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getRemotePools", remoteChainSelector) + + if err != nil { + return *new([][]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][]byte)).(*[][]byte) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetRemotePools(remoteChainSelector uint64) ([][]byte, error) { + return _BurnToAddressMintTokenPool.Contract.GetRemotePools(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetRemotePools(remoteChainSelector uint64) ([][]byte, error) { + return _BurnToAddressMintTokenPool.Contract.GetRemotePools(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) { + return _BurnToAddressMintTokenPool.Contract.GetRemoteToken(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) { + return _BurnToAddressMintTokenPool.Contract.GetRemoteToken(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getRmnProxy") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetRmnProxy() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetRmnProxy(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetRmnProxy() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetRmnProxy(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getRouter") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetRouter() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetRouter(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetRouter() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetRouter(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getSupportedChains") + + if err != nil { + return *new([]uint64), err + } + + out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetSupportedChains() ([]uint64, error) { + return _BurnToAddressMintTokenPool.Contract.GetSupportedChains(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) { + return _BurnToAddressMintTokenPool.Contract.GetSupportedChains(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetToken() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetToken(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetToken() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.GetToken(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) GetTokenDecimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "getTokenDecimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) GetTokenDecimals() (uint8, error) { + return _BurnToAddressMintTokenPool.Contract.GetTokenDecimals(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) GetTokenDecimals() (uint8, error) { + return _BurnToAddressMintTokenPool.Contract.GetTokenDecimals(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) IBurnAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "i_burnAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) IBurnAddress() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.IBurnAddress(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) IBurnAddress() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.IBurnAddress(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) IsRemotePool(opts *bind.CallOpts, remoteChainSelector uint64, remotePoolAddress []byte) (bool, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "isRemotePool", remoteChainSelector, remotePoolAddress) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) IsRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (bool, error) { + return _BurnToAddressMintTokenPool.Contract.IsRemotePool(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector, remotePoolAddress) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) IsRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (bool, error) { + return _BurnToAddressMintTokenPool.Contract.IsRemotePool(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector, remotePoolAddress) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) { + return _BurnToAddressMintTokenPool.Contract.IsSupportedChain(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) { + return _BurnToAddressMintTokenPool.Contract.IsSupportedChain(&_BurnToAddressMintTokenPool.CallOpts, remoteChainSelector) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "isSupportedToken", token) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) IsSupportedToken(token common.Address) (bool, error) { + return _BurnToAddressMintTokenPool.Contract.IsSupportedToken(&_BurnToAddressMintTokenPool.CallOpts, token) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) IsSupportedToken(token common.Address) (bool, error) { + return _BurnToAddressMintTokenPool.Contract.IsSupportedToken(&_BurnToAddressMintTokenPool.CallOpts, token) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) Owner() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.Owner(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) Owner() (common.Address, error) { + return _BurnToAddressMintTokenPool.Contract.Owner(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _BurnToAddressMintTokenPool.Contract.SupportsInterface(&_BurnToAddressMintTokenPool.CallOpts, interfaceId) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _BurnToAddressMintTokenPool.Contract.SupportsInterface(&_BurnToAddressMintTokenPool.CallOpts, interfaceId) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _BurnToAddressMintTokenPool.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) TypeAndVersion() (string, error) { + return _BurnToAddressMintTokenPool.Contract.TypeAndVersion(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolCallerSession) TypeAndVersion() (string, error) { + return _BurnToAddressMintTokenPool.Contract.TypeAndVersion(&_BurnToAddressMintTokenPool.CallOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "acceptOwnership") +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) AcceptOwnership() (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.AcceptOwnership(&_BurnToAddressMintTokenPool.TransactOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.AcceptOwnership(&_BurnToAddressMintTokenPool.TransactOpts) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) AddRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "addRemotePool", remoteChainSelector, remotePoolAddress) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) AddRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.AddRemotePool(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) AddRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.AddRemotePool(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnToAddressMintTokenPool.TransactOpts, removes, adds) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnToAddressMintTokenPool.TransactOpts, removes, adds) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, remoteChainSelectorsToRemove []uint64, chainsToAdd []TokenPoolChainUpdate) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "applyChainUpdates", remoteChainSelectorsToRemove, chainsToAdd) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) ApplyChainUpdates(remoteChainSelectorsToRemove []uint64, chainsToAdd []TokenPoolChainUpdate) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.ApplyChainUpdates(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelectorsToRemove, chainsToAdd) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) ApplyChainUpdates(remoteChainSelectorsToRemove []uint64, chainsToAdd []TokenPoolChainUpdate) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.ApplyChainUpdates(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelectorsToRemove, chainsToAdd) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "lockOrBurn", lockOrBurnIn) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.LockOrBurn(&_BurnToAddressMintTokenPool.TransactOpts, lockOrBurnIn) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.LockOrBurn(&_BurnToAddressMintTokenPool.TransactOpts, lockOrBurnIn) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "releaseOrMint", releaseOrMintIn) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.ReleaseOrMint(&_BurnToAddressMintTokenPool.TransactOpts, releaseOrMintIn) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.ReleaseOrMint(&_BurnToAddressMintTokenPool.TransactOpts, releaseOrMintIn) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) RemoveRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "removeRemotePool", remoteChainSelector, remotePoolAddress) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) RemoveRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.RemoveRemotePool(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) RemoveRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.RemoveRemotePool(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) SetChainRateLimiterConfigs(opts *bind.TransactOpts, remoteChainSelectors []uint64, outboundConfigs []RateLimiterConfig, inboundConfigs []RateLimiterConfig) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "setChainRateLimiterConfigs", remoteChainSelectors, outboundConfigs, inboundConfigs) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) SetChainRateLimiterConfigs(remoteChainSelectors []uint64, outboundConfigs []RateLimiterConfig, inboundConfigs []RateLimiterConfig) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.SetChainRateLimiterConfigs(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelectors, outboundConfigs, inboundConfigs) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) SetChainRateLimiterConfigs(remoteChainSelectors []uint64, outboundConfigs []RateLimiterConfig, inboundConfigs []RateLimiterConfig) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.SetChainRateLimiterConfigs(&_BurnToAddressMintTokenPool.TransactOpts, remoteChainSelectors, outboundConfigs, inboundConfigs) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "setRateLimitAdmin", rateLimitAdmin) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.SetRateLimitAdmin(&_BurnToAddressMintTokenPool.TransactOpts, rateLimitAdmin) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.SetRateLimitAdmin(&_BurnToAddressMintTokenPool.TransactOpts, rateLimitAdmin) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "setRouter", newRouter) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.SetRouter(&_BurnToAddressMintTokenPool.TransactOpts, newRouter) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.SetRouter(&_BurnToAddressMintTokenPool.TransactOpts, newRouter) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.contract.Transact(opts, "transferOwnership", to) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.TransferOwnership(&_BurnToAddressMintTokenPool.TransactOpts, to) +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _BurnToAddressMintTokenPool.Contract.TransferOwnership(&_BurnToAddressMintTokenPool.TransactOpts, to) +} + +type BurnToAddressMintTokenPoolAllowListAddIterator struct { + Event *BurnToAddressMintTokenPoolAllowListAdd + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolAllowListAddIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolAllowListAdd) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolAllowListAdd) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolAllowListAddIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolAllowListAddIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolAllowListAdd struct { + Sender common.Address + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolAllowListAddIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "AllowListAdd") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolAllowListAddIterator{contract: _BurnToAddressMintTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolAllowListAdd) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "AllowListAdd") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolAllowListAdd) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*BurnToAddressMintTokenPoolAllowListAdd, error) { + event := new(BurnToAddressMintTokenPoolAllowListAdd) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolAllowListRemoveIterator struct { + Event *BurnToAddressMintTokenPoolAllowListRemove + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolAllowListRemoveIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolAllowListRemove) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolAllowListRemove) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolAllowListRemoveIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolAllowListRemoveIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolAllowListRemove struct { + Sender common.Address + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolAllowListRemoveIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "AllowListRemove") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolAllowListRemoveIterator{contract: _BurnToAddressMintTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolAllowListRemove) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "AllowListRemove") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolAllowListRemove) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*BurnToAddressMintTokenPoolAllowListRemove, error) { + event := new(BurnToAddressMintTokenPoolAllowListRemove) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolBurnedIterator struct { + Event *BurnToAddressMintTokenPoolBurned + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolBurnedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolBurned) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolBurned) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolBurnedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolBurnedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolBurned struct { + Sender common.Address + Amount *big.Int + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnToAddressMintTokenPoolBurnedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "Burned", senderRule) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolBurnedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolBurned, sender []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "Burned", senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolBurned) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "Burned", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseBurned(log types.Log) (*BurnToAddressMintTokenPoolBurned, error) { + event := new(BurnToAddressMintTokenPoolBurned) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "Burned", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolChainAddedIterator struct { + Event *BurnToAddressMintTokenPoolChainAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolChainAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolChainAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolChainAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolChainAddedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolChainAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolChainAdded struct { + RemoteChainSelector uint64 + RemoteToken []byte + OutboundRateLimiterConfig RateLimiterConfig + InboundRateLimiterConfig RateLimiterConfig + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolChainAddedIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "ChainAdded") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolChainAddedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolChainAdded) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "ChainAdded") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolChainAdded) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseChainAdded(log types.Log) (*BurnToAddressMintTokenPoolChainAdded, error) { + event := new(BurnToAddressMintTokenPoolChainAdded) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolChainConfiguredIterator struct { + Event *BurnToAddressMintTokenPoolChainConfigured + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolChainConfiguredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolChainConfigured) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolChainConfigured) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolChainConfiguredIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolChainConfiguredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolChainConfigured struct { + RemoteChainSelector uint64 + OutboundRateLimiterConfig RateLimiterConfig + InboundRateLimiterConfig RateLimiterConfig + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolChainConfiguredIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "ChainConfigured") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolChainConfiguredIterator{contract: _BurnToAddressMintTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolChainConfigured) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "ChainConfigured") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolChainConfigured) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseChainConfigured(log types.Log) (*BurnToAddressMintTokenPoolChainConfigured, error) { + event := new(BurnToAddressMintTokenPoolChainConfigured) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolChainRemovedIterator struct { + Event *BurnToAddressMintTokenPoolChainRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolChainRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolChainRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolChainRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolChainRemovedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolChainRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolChainRemoved struct { + RemoteChainSelector uint64 + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolChainRemovedIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "ChainRemoved") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolChainRemovedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolChainRemoved) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "ChainRemoved") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolChainRemoved) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseChainRemoved(log types.Log) (*BurnToAddressMintTokenPoolChainRemoved, error) { + event := new(BurnToAddressMintTokenPoolChainRemoved) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolConfigChangedIterator struct { + Event *BurnToAddressMintTokenPoolConfigChanged + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolConfigChangedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolConfigChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolConfigChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolConfigChangedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolConfigChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolConfigChanged struct { + Config RateLimiterConfig + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolConfigChangedIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "ConfigChanged") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolConfigChangedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolConfigChanged) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "ConfigChanged") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolConfigChanged) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseConfigChanged(log types.Log) (*BurnToAddressMintTokenPoolConfigChanged, error) { + event := new(BurnToAddressMintTokenPoolConfigChanged) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolLockedIterator struct { + Event *BurnToAddressMintTokenPoolLocked + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolLockedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolLocked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolLocked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolLockedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolLockedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolLocked struct { + Sender common.Address + Amount *big.Int + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnToAddressMintTokenPoolLockedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "Locked", senderRule) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolLockedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolLocked, sender []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "Locked", senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolLocked) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "Locked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseLocked(log types.Log) (*BurnToAddressMintTokenPoolLocked, error) { + event := new(BurnToAddressMintTokenPoolLocked) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "Locked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolMintedIterator struct { + Event *BurnToAddressMintTokenPoolMinted + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolMintedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolMinted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolMinted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolMintedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolMintedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolMinted struct { + Sender common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnToAddressMintTokenPoolMintedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolMintedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolMinted) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "Minted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseMinted(log types.Log) (*BurnToAddressMintTokenPoolMinted, error) { + event := new(BurnToAddressMintTokenPoolMinted) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "Minted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolOwnershipTransferRequestedIterator struct { + Event *BurnToAddressMintTokenPoolOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnToAddressMintTokenPoolOwnershipTransferRequestedIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolOwnershipTransferRequestedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolOwnershipTransferRequested) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*BurnToAddressMintTokenPoolOwnershipTransferRequested, error) { + event := new(BurnToAddressMintTokenPoolOwnershipTransferRequested) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolOwnershipTransferredIterator struct { + Event *BurnToAddressMintTokenPoolOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnToAddressMintTokenPoolOwnershipTransferredIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolOwnershipTransferredIterator{contract: _BurnToAddressMintTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolOwnershipTransferred) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*BurnToAddressMintTokenPoolOwnershipTransferred, error) { + event := new(BurnToAddressMintTokenPoolOwnershipTransferred) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolRateLimitAdminSetIterator struct { + Event *BurnToAddressMintTokenPoolRateLimitAdminSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolRateLimitAdminSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolRateLimitAdminSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolRateLimitAdminSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolRateLimitAdminSetIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolRateLimitAdminSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolRateLimitAdminSet struct { + RateLimitAdmin common.Address + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterRateLimitAdminSet(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolRateLimitAdminSetIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "RateLimitAdminSet") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolRateLimitAdminSetIterator{contract: _BurnToAddressMintTokenPool.contract, event: "RateLimitAdminSet", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchRateLimitAdminSet(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolRateLimitAdminSet) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "RateLimitAdminSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolRateLimitAdminSet) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "RateLimitAdminSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseRateLimitAdminSet(log types.Log) (*BurnToAddressMintTokenPoolRateLimitAdminSet, error) { + event := new(BurnToAddressMintTokenPoolRateLimitAdminSet) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "RateLimitAdminSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolReleasedIterator struct { + Event *BurnToAddressMintTokenPoolReleased + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolReleasedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolReleased) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolReleased) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolReleasedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolReleasedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolReleased struct { + Sender common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnToAddressMintTokenPoolReleasedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolReleasedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolReleased) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "Released", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseReleased(log types.Log) (*BurnToAddressMintTokenPoolReleased, error) { + event := new(BurnToAddressMintTokenPoolReleased) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "Released", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolRemotePoolAddedIterator struct { + Event *BurnToAddressMintTokenPoolRemotePoolAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolRemotePoolAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolRemotePoolAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolRemotePoolAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolRemotePoolAddedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolRemotePoolAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolRemotePoolAdded struct { + RemoteChainSelector uint64 + RemotePoolAddress []byte + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterRemotePoolAdded(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnToAddressMintTokenPoolRemotePoolAddedIterator, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "RemotePoolAdded", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolRemotePoolAddedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "RemotePoolAdded", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchRemotePoolAdded(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolRemotePoolAdded, remoteChainSelector []uint64) (event.Subscription, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "RemotePoolAdded", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolRemotePoolAdded) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "RemotePoolAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseRemotePoolAdded(log types.Log) (*BurnToAddressMintTokenPoolRemotePoolAdded, error) { + event := new(BurnToAddressMintTokenPoolRemotePoolAdded) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "RemotePoolAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolRemotePoolRemovedIterator struct { + Event *BurnToAddressMintTokenPoolRemotePoolRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolRemotePoolRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolRemotePoolRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolRemotePoolRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolRemotePoolRemovedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolRemotePoolRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolRemotePoolRemoved struct { + RemoteChainSelector uint64 + RemotePoolAddress []byte + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterRemotePoolRemoved(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnToAddressMintTokenPoolRemotePoolRemovedIterator, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "RemotePoolRemoved", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolRemotePoolRemovedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "RemotePoolRemoved", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchRemotePoolRemoved(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolRemotePoolRemoved, remoteChainSelector []uint64) (event.Subscription, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "RemotePoolRemoved", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolRemotePoolRemoved) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "RemotePoolRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseRemotePoolRemoved(log types.Log) (*BurnToAddressMintTokenPoolRemotePoolRemoved, error) { + event := new(BurnToAddressMintTokenPoolRemotePoolRemoved) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "RemotePoolRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolRouterUpdatedIterator struct { + Event *BurnToAddressMintTokenPoolRouterUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolRouterUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolRouterUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolRouterUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolRouterUpdatedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolRouterUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolRouterUpdated struct { + OldRouter common.Address + NewRouter common.Address + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolRouterUpdatedIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "RouterUpdated") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolRouterUpdatedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolRouterUpdated) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "RouterUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolRouterUpdated) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*BurnToAddressMintTokenPoolRouterUpdated, error) { + event := new(BurnToAddressMintTokenPoolRouterUpdated) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type BurnToAddressMintTokenPoolTokensConsumedIterator struct { + Event *BurnToAddressMintTokenPoolTokensConsumed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *BurnToAddressMintTokenPoolTokensConsumedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolTokensConsumed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(BurnToAddressMintTokenPoolTokensConsumed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *BurnToAddressMintTokenPoolTokensConsumedIterator) Error() error { + return it.fail +} + +func (it *BurnToAddressMintTokenPoolTokensConsumedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type BurnToAddressMintTokenPoolTokensConsumed struct { + Tokens *big.Int + Raw types.Log +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolTokensConsumedIterator, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.FilterLogs(opts, "TokensConsumed") + if err != nil { + return nil, err + } + return &BurnToAddressMintTokenPoolTokensConsumedIterator{contract: _BurnToAddressMintTokenPool.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolTokensConsumed) (event.Subscription, error) { + + logs, sub, err := _BurnToAddressMintTokenPool.contract.WatchLogs(opts, "TokensConsumed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(BurnToAddressMintTokenPoolTokensConsumed) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPoolFilterer) ParseTokensConsumed(log types.Log) (*BurnToAddressMintTokenPoolTokensConsumed, error) { + event := new(BurnToAddressMintTokenPoolTokensConsumed) + if err := _BurnToAddressMintTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _BurnToAddressMintTokenPool.abi.Events["AllowListAdd"].ID: + return _BurnToAddressMintTokenPool.ParseAllowListAdd(log) + case _BurnToAddressMintTokenPool.abi.Events["AllowListRemove"].ID: + return _BurnToAddressMintTokenPool.ParseAllowListRemove(log) + case _BurnToAddressMintTokenPool.abi.Events["Burned"].ID: + return _BurnToAddressMintTokenPool.ParseBurned(log) + case _BurnToAddressMintTokenPool.abi.Events["ChainAdded"].ID: + return _BurnToAddressMintTokenPool.ParseChainAdded(log) + case _BurnToAddressMintTokenPool.abi.Events["ChainConfigured"].ID: + return _BurnToAddressMintTokenPool.ParseChainConfigured(log) + case _BurnToAddressMintTokenPool.abi.Events["ChainRemoved"].ID: + return _BurnToAddressMintTokenPool.ParseChainRemoved(log) + case _BurnToAddressMintTokenPool.abi.Events["ConfigChanged"].ID: + return _BurnToAddressMintTokenPool.ParseConfigChanged(log) + case _BurnToAddressMintTokenPool.abi.Events["Locked"].ID: + return _BurnToAddressMintTokenPool.ParseLocked(log) + case _BurnToAddressMintTokenPool.abi.Events["Minted"].ID: + return _BurnToAddressMintTokenPool.ParseMinted(log) + case _BurnToAddressMintTokenPool.abi.Events["OwnershipTransferRequested"].ID: + return _BurnToAddressMintTokenPool.ParseOwnershipTransferRequested(log) + case _BurnToAddressMintTokenPool.abi.Events["OwnershipTransferred"].ID: + return _BurnToAddressMintTokenPool.ParseOwnershipTransferred(log) + case _BurnToAddressMintTokenPool.abi.Events["RateLimitAdminSet"].ID: + return _BurnToAddressMintTokenPool.ParseRateLimitAdminSet(log) + case _BurnToAddressMintTokenPool.abi.Events["Released"].ID: + return _BurnToAddressMintTokenPool.ParseReleased(log) + case _BurnToAddressMintTokenPool.abi.Events["RemotePoolAdded"].ID: + return _BurnToAddressMintTokenPool.ParseRemotePoolAdded(log) + case _BurnToAddressMintTokenPool.abi.Events["RemotePoolRemoved"].ID: + return _BurnToAddressMintTokenPool.ParseRemotePoolRemoved(log) + case _BurnToAddressMintTokenPool.abi.Events["RouterUpdated"].ID: + return _BurnToAddressMintTokenPool.ParseRouterUpdated(log) + case _BurnToAddressMintTokenPool.abi.Events["TokensConsumed"].ID: + return _BurnToAddressMintTokenPool.ParseTokensConsumed(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (BurnToAddressMintTokenPoolAllowListAdd) Topic() common.Hash { + return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8") +} + +func (BurnToAddressMintTokenPoolAllowListRemove) Topic() common.Hash { + return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566") +} + +func (BurnToAddressMintTokenPoolBurned) Topic() common.Hash { + return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7") +} + +func (BurnToAddressMintTokenPoolChainAdded) Topic() common.Hash { + return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2") +} + +func (BurnToAddressMintTokenPoolChainConfigured) Topic() common.Hash { + return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b") +} + +func (BurnToAddressMintTokenPoolChainRemoved) Topic() common.Hash { + return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916") +} + +func (BurnToAddressMintTokenPoolConfigChanged) Topic() common.Hash { + return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19") +} + +func (BurnToAddressMintTokenPoolLocked) Topic() common.Hash { + return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008") +} + +func (BurnToAddressMintTokenPoolMinted) Topic() common.Hash { + return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0") +} + +func (BurnToAddressMintTokenPoolOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (BurnToAddressMintTokenPoolOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (BurnToAddressMintTokenPoolRateLimitAdminSet) Topic() common.Hash { + return common.HexToHash("0x44676b5284b809a22248eba0da87391d79098be38bb03154be88a58bf4d09174") +} + +func (BurnToAddressMintTokenPoolReleased) Topic() common.Hash { + return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52") +} + +func (BurnToAddressMintTokenPoolRemotePoolAdded) Topic() common.Hash { + return common.HexToHash("0x7d628c9a1796743d365ab521a8b2a4686e419b3269919dc9145ea2ce853b54ea") +} + +func (BurnToAddressMintTokenPoolRemotePoolRemoved) Topic() common.Hash { + return common.HexToHash("0x52d00ee4d9bd51b40168f2afc5848837288ce258784ad914278791464b3f4d76") +} + +func (BurnToAddressMintTokenPoolRouterUpdated) Topic() common.Hash { + return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684") +} + +func (BurnToAddressMintTokenPoolTokensConsumed) Topic() common.Hash { + return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a") +} + +func (_BurnToAddressMintTokenPool *BurnToAddressMintTokenPool) Address() common.Address { + return _BurnToAddressMintTokenPool.address +} + +type BurnToAddressMintTokenPoolInterface interface { + GetAllowList(opts *bind.CallOpts) ([]common.Address, error) + + GetAllowListEnabled(opts *bind.CallOpts) (bool, error) + + GetBurnAddress(opts *bind.CallOpts) (common.Address, error) + + GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) + + GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) + + GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error) + + GetRemotePools(opts *bind.CallOpts, remoteChainSelector uint64) ([][]byte, error) + + GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) + + GetRmnProxy(opts *bind.CallOpts) (common.Address, error) + + GetRouter(opts *bind.CallOpts) (common.Address, error) + + GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) + + GetToken(opts *bind.CallOpts) (common.Address, error) + + GetTokenDecimals(opts *bind.CallOpts) (uint8, error) + + IBurnAddress(opts *bind.CallOpts) (common.Address, error) + + IsRemotePool(opts *bind.CallOpts, remoteChainSelector uint64, remotePoolAddress []byte) (bool, error) + + IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) + + IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AddRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) + + ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) + + ApplyChainUpdates(opts *bind.TransactOpts, remoteChainSelectorsToRemove []uint64, chainsToAdd []TokenPoolChainUpdate) (*types.Transaction, error) + + LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) + + ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) + + RemoveRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) + + SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) + + SetChainRateLimiterConfigs(opts *bind.TransactOpts, remoteChainSelectors []uint64, outboundConfigs []RateLimiterConfig, inboundConfigs []RateLimiterConfig) (*types.Transaction, error) + + SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error) + + SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + FilterAllowListAdd(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolAllowListAddIterator, error) + + WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolAllowListAdd) (event.Subscription, error) + + ParseAllowListAdd(log types.Log) (*BurnToAddressMintTokenPoolAllowListAdd, error) + + FilterAllowListRemove(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolAllowListRemoveIterator, error) + + WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolAllowListRemove) (event.Subscription, error) + + ParseAllowListRemove(log types.Log) (*BurnToAddressMintTokenPoolAllowListRemove, error) + + FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnToAddressMintTokenPoolBurnedIterator, error) + + WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolBurned, sender []common.Address) (event.Subscription, error) + + ParseBurned(log types.Log) (*BurnToAddressMintTokenPoolBurned, error) + + FilterChainAdded(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolChainAddedIterator, error) + + WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolChainAdded) (event.Subscription, error) + + ParseChainAdded(log types.Log) (*BurnToAddressMintTokenPoolChainAdded, error) + + FilterChainConfigured(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolChainConfiguredIterator, error) + + WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolChainConfigured) (event.Subscription, error) + + ParseChainConfigured(log types.Log) (*BurnToAddressMintTokenPoolChainConfigured, error) + + FilterChainRemoved(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolChainRemovedIterator, error) + + WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolChainRemoved) (event.Subscription, error) + + ParseChainRemoved(log types.Log) (*BurnToAddressMintTokenPoolChainRemoved, error) + + FilterConfigChanged(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolConfigChangedIterator, error) + + WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolConfigChanged) (event.Subscription, error) + + ParseConfigChanged(log types.Log) (*BurnToAddressMintTokenPoolConfigChanged, error) + + FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnToAddressMintTokenPoolLockedIterator, error) + + WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolLocked, sender []common.Address) (event.Subscription, error) + + ParseLocked(log types.Log) (*BurnToAddressMintTokenPoolLocked, error) + + FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnToAddressMintTokenPoolMintedIterator, error) + + WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) + + ParseMinted(log types.Log) (*BurnToAddressMintTokenPoolMinted, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnToAddressMintTokenPoolOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*BurnToAddressMintTokenPoolOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnToAddressMintTokenPoolOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*BurnToAddressMintTokenPoolOwnershipTransferred, error) + + FilterRateLimitAdminSet(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolRateLimitAdminSetIterator, error) + + WatchRateLimitAdminSet(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolRateLimitAdminSet) (event.Subscription, error) + + ParseRateLimitAdminSet(log types.Log) (*BurnToAddressMintTokenPoolRateLimitAdminSet, error) + + FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnToAddressMintTokenPoolReleasedIterator, error) + + WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) + + ParseReleased(log types.Log) (*BurnToAddressMintTokenPoolReleased, error) + + FilterRemotePoolAdded(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnToAddressMintTokenPoolRemotePoolAddedIterator, error) + + WatchRemotePoolAdded(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolRemotePoolAdded, remoteChainSelector []uint64) (event.Subscription, error) + + ParseRemotePoolAdded(log types.Log) (*BurnToAddressMintTokenPoolRemotePoolAdded, error) + + FilterRemotePoolRemoved(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnToAddressMintTokenPoolRemotePoolRemovedIterator, error) + + WatchRemotePoolRemoved(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolRemotePoolRemoved, remoteChainSelector []uint64) (event.Subscription, error) + + ParseRemotePoolRemoved(log types.Log) (*BurnToAddressMintTokenPoolRemotePoolRemoved, error) + + FilterRouterUpdated(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolRouterUpdatedIterator, error) + + WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolRouterUpdated) (event.Subscription, error) + + ParseRouterUpdated(log types.Log) (*BurnToAddressMintTokenPoolRouterUpdated, error) + + FilterTokensConsumed(opts *bind.FilterOpts) (*BurnToAddressMintTokenPoolTokensConsumedIterator, error) + + WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnToAddressMintTokenPoolTokensConsumed) (event.Subscription, error) + + ParseTokensConsumed(log types.Log) (*BurnToAddressMintTokenPoolTokensConsumed, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/ccip/generated/siloed_lock_release_token_pool/siloed_lock_release_token_pool.go b/core/gethwrappers/ccip/generated/siloed_lock_release_token_pool/siloed_lock_release_token_pool.go new file mode 100644 index 00000000000..b69ab8d64dc --- /dev/null +++ b/core/gethwrappers/ccip/generated/siloed_lock_release_token_pool/siloed_lock_release_token_pool.go @@ -0,0 +1,4197 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package siloed_lock_release_token_pool + +import ( + "errors" + "fmt" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +type PoolLockOrBurnInV1 struct { + Receiver []byte + RemoteChainSelector uint64 + OriginalSender common.Address + Amount *big.Int + LocalToken common.Address +} + +type PoolLockOrBurnOutV1 struct { + DestTokenAddress []byte + DestPoolData []byte +} + +type PoolReleaseOrMintInV1 struct { + OriginalSender []byte + RemoteChainSelector uint64 + Receiver common.Address + Amount *big.Int + LocalToken common.Address + SourcePoolAddress []byte + SourcePoolData []byte + OffchainTokenData []byte +} + +type PoolReleaseOrMintOutV1 struct { + DestinationAmount *big.Int +} + +type RateLimiterConfig struct { + IsEnabled bool + Capacity *big.Int + Rate *big.Int +} + +type RateLimiterTokenBucket struct { + Tokens *big.Int + LastUpdated uint32 + IsEnabled bool + Capacity *big.Int + Rate *big.Int +} + +type SiloedLockReleaseTokenPoolSiloConfigUpdate struct { + RemoteChainSelector uint64 + Rebalancer common.Address +} + +type TokenPoolChainUpdate struct { + RemoteChainSelector uint64 + RemotePoolAddresses [][]byte + RemoteTokenAddress []byte + OutboundRateLimiterConfig RateLimiterConfig + InboundRateLimiterConfig RateLimiterConfig +} + +var SiloedLockReleaseTokenPoolMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"localTokenDecimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"allowlist\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"rmnProxy\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"router\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"acceptOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addRemotePool\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"applyAllowListUpdates\",\"inputs\":[{\"name\":\"removes\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"adds\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"applyChainUpdates\",\"inputs\":[{\"name\":\"remoteChainSelectorsToRemove\",\"type\":\"uint64[]\",\"internalType\":\"uint64[]\"},{\"name\":\"chainsToAdd\",\"type\":\"tuple[]\",\"internalType\":\"structTokenPool.ChainUpdate[]\",\"components\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddresses\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"remoteTokenAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getAllowList\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllowListEnabled\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAvailableTokens\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"lockedTokens\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentInboundRateLimiterState\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.TokenBucket\",\"components\":[{\"name\":\"tokens\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"lastUpdated\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentOutboundRateLimiterState\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.TokenBucket\",\"components\":[{\"name\":\"tokens\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"lastUpdated\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRateLimitAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRebalancer\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRemotePools\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRemoteToken\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRmnProxy\",\"inputs\":[],\"outputs\":[{\"name\":\"rmnProxy\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRouter\",\"inputs\":[],\"outputs\":[{\"name\":\"router\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSiloRebalancer\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSupportedChains\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64[]\",\"internalType\":\"uint64[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getToken\",\"inputs\":[],\"outputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getTokenDecimals\",\"inputs\":[],\"outputs\":[{\"name\":\"decimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getUnsiloedLiquidity\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRemotePool\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSiloed\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSupportedChain\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSupportedToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"lockOrBurn\",\"inputs\":[{\"name\":\"lockOrBurnIn\",\"type\":\"tuple\",\"internalType\":\"structPool.LockOrBurnInV1\",\"components\":[{\"name\":\"receiver\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"originalSender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"localToken\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structPool.LockOrBurnOutV1\",\"components\":[{\"name\":\"destTokenAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"destPoolData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"provideLiquidity\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"provideSiloedLiquidity\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"releaseOrMint\",\"inputs\":[{\"name\":\"releaseOrMintIn\",\"type\":\"tuple\",\"internalType\":\"structPool.ReleaseOrMintInV1\",\"components\":[{\"name\":\"originalSender\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"localToken\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"sourcePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"sourcePoolData\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"offchainTokenData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"components\":[{\"name\":\"destinationAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeRemotePool\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setChainRateLimiterConfig\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"outboundConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setChainRateLimiterConfigs\",\"inputs\":[{\"name\":\"remoteChainSelectors\",\"type\":\"uint64[]\",\"internalType\":\"uint64[]\"},{\"name\":\"outboundConfigs\",\"type\":\"tuple[]\",\"internalType\":\"structRateLimiter.Config[]\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundConfigs\",\"type\":\"tuple[]\",\"internalType\":\"structRateLimiter.Config[]\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRateLimitAdmin\",\"inputs\":[{\"name\":\"rateLimitAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRebalancer\",\"inputs\":[{\"name\":\"newRebalancer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRouter\",\"inputs\":[{\"name\":\"newRouter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setSiloRebalancer\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"newRebalancer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"typeAndVersion\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"updateSiloDesignations\",\"inputs\":[{\"name\":\"removes\",\"type\":\"uint64[]\",\"internalType\":\"uint64[]\"},{\"name\":\"adds\",\"type\":\"tuple[]\",\"internalType\":\"structSiloedLockReleaseTokenPool.SiloConfigUpdate[]\",\"components\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"rebalancer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawLiquidity\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSiloedLiquidity\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AllowListAdd\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AllowListRemove\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Burned\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChainAdded\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"remoteToken\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChainConfigured\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChainRemoved\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChainSiloed\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"rebalancer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChainUnsiloed\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"amountUnsiloed\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ConfigChanged\",\"inputs\":[{\"name\":\"config\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"LiquidityAdded\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"provider\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"LiquidityRemoved\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"remover\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Locked\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Minted\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferRequested\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RateLimitAdminSet\",\"inputs\":[{\"name\":\"rateLimitAdmin\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Released\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RemotePoolAdded\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RemotePoolRemoved\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RouterUpdated\",\"inputs\":[{\"name\":\"oldRouter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newRouter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SiloRebalancerSet\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"oldRebalancer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newRebalancer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokensConsumed\",\"inputs\":[{\"name\":\"tokens\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnsiloedRebalancerSet\",\"inputs\":[{\"name\":\"oldRebalancer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newRebalancer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AggregateValueMaxCapacityExceeded\",\"inputs\":[{\"name\":\"capacity\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"requested\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"AggregateValueRateLimitReached\",\"inputs\":[{\"name\":\"minWaitInSeconds\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"available\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"AllowListNotEnabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BucketOverfilled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CallerIsNotARampOnRouter\",\"inputs\":[{\"name\":\"caller\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"CannotTransferToSelf\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ChainAlreadyExists\",\"inputs\":[{\"name\":\"chainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"ChainNotAllowed\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"ChainNotSiloed\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"CursedByRMN\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DisabledNonZeroRateLimit\",\"inputs\":[{\"name\":\"config\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}]},{\"type\":\"error\",\"name\":\"InsufficientLiquidity\",\"inputs\":[{\"name\":\"availableLiquidity\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"requestedAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidChainSelector\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"InvalidDecimalArgs\",\"inputs\":[{\"name\":\"expected\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"actual\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"type\":\"error\",\"name\":\"InvalidRateLimitRate\",\"inputs\":[{\"name\":\"rateLimiterConfig\",\"type\":\"tuple\",\"internalType\":\"structRateLimiter.Config\",\"components\":[{\"name\":\"isEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"capacity\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"rate\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}]},{\"type\":\"error\",\"name\":\"InvalidRemoteChainDecimals\",\"inputs\":[{\"name\":\"sourcePoolData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"InvalidRemotePoolForChain\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"InvalidSourcePoolAddress\",\"inputs\":[{\"name\":\"sourcePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"InvalidToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"LiquidityAmountCannotBeZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MismatchedArrayLengths\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MustBeProposedOwner\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NonExistentChain\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"OnlyCallableByOwner\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OverflowDetected\",\"inputs\":[{\"name\":\"remoteDecimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"localDecimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"remoteAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"OwnerCannotBeZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"PoolAlreadyAdded\",\"inputs\":[{\"name\":\"remoteChainSelector\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"remotePoolAddress\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"RateLimitMustBeDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SenderNotAllowed\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"TokenMaxCapacityExceeded\",\"inputs\":[{\"name\":\"capacity\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"requested\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"tokenAddress\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"TokenRateLimitReached\",\"inputs\":[{\"name\":\"minWaitInSeconds\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"available\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"tokenAddress\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[{\"name\":\"caller\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ZeroAddressNotAllowed\",\"inputs\":[]}]", + Bin: "0x61010080604052346103775761550d803803809161001d82856103f6565b833981019060a0818303126103775780516001600160a01b038116918282036103775761004c60208201610419565b60408201519092906001600160401b0381116103775782019480601f87011215610377578551956001600160401b0387116103e0578660051b906020820197610098604051998a6103f6565b885260208089019282010192831161037757602001905b8282106103c8575050506100d160806100ca60608501610427565b9301610427565b9333156103b757600180546001600160a01b03191633179055801580156103a6575b8015610395575b6103845760049260209260805260c0526040519283809263313ce56760e01b82525afa60009181610343575b50610318575b5060a052600480546001600160a01b0319166001600160a01b03929092169190911790558051151560e08190526101fa575b604051614f3190816105dc82396080518181816103e4015281816110950152818161187401528181611a6e0152818161295a01528181612b3801528181612f1a01528181612f7401526130dc015260a051818181611b2e01528181612ec301528181613b0c0152613b8f015260c051818181610df90152818161190f01526129f6015260e051818181610da701528181611953015261275b0152f35b604051602061020981836103f6565b60008252600036813760e051156103075760005b8251811015610284576001906001600160a01b0361023b828661043b565b5116836102478261047d565b610254575b50500161021d565b7f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf756691604051908152a1388361024c565b50905060005b82518110156102fe576001906001600160a01b036102a8828661043b565b511680156102f857836102ba8261057b565b6102c8575b50505b0161028a565b7f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d891604051908152a138836102bf565b506102c2565b5050503861015e565b6335f4a7b360e01b60005260046000fd5b60ff1660ff821681810361032c575061012c565b6332ad3e0760e11b60005260045260245260446000fd5b9091506020813d60201161037c575b8161035f602093836103f6565b810103126103775761037090610419565b9038610126565b600080fd5b3d9150610352565b6342bcdf7f60e11b60005260046000fd5b506001600160a01b038316156100fa565b506001600160a01b038516156100f3565b639b15e16f60e01b60005260046000fd5b602080916103d584610427565b8152019101906100af565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b038211908210176103e057604052565b519060ff8216820361037757565b51906001600160a01b038216820361037757565b805182101561044f5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b805482101561044f5760005260206000200190600090565b600081815260036020526040902054801561057457600019810181811161055e5760025460001981019190821161055e5781810361050d575b50505060025480156104f757600019016104d1816002610465565b8154906000199060031b1b19169055600255600052600360205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b61054661051e61052f936002610465565b90549060031b1c9283926002610465565b819391549060031b91821b91600019901b19161790565b905560005260036020526040600020553880806104b6565b634e487b7160e01b600052601160045260246000fd5b5050600090565b806000526003602052604060002054156000146105d557600254680100000000000000008110156103e0576105bc61052f8260018594016002556002610465565b9055600254906000526003602052604060002055600190565b5060009056fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a714613152575080630a861f2a1461301e578063181f5a7714612f9857806321df0da714612f47578063240028e814612ee757806324f65ee714612ea95780632d4a148f14612d6d57806331238ffc14612d2757806339077537146128f0578063432a6ba3146128bc5780634c5ef0ed146128a357806354c8a4f31461272957806362ddd3c4146126a65780636600f92c1461258a5780636cfd1553146124d05780636d3d1a581461249c5780636d9d216c146120cc57806379ba5097146120015780637d54534e14611f745780638926f54f14611f2f5780638da5cb5b14611efb578063962d402014611da55780639a4575b914611809578063a42a7b8b1461169b578063a7cd63b7146115e7578063acfecf91146114c7578063af0e58b9146114a9578063af58d59f1461145f578063b0f479a11461142b578063b7946580146113f3578063c0d786551461130b578063c4bffe2b146111db578063c75eea9c14611132578063ce3c752814610fd5578063cf7401f314610e5e578063d70be92f14610e1d578063dc0bd97114610dcc578063e0351e1314610d8f578063e8a1da17146104aa578063eb521a4c146102ef578063f1e73399146102c45763f2fde38b146101ed57600080fd5b346102bf5760206003193601126102bf5773ffffffffffffffffffffffffffffffffffffffff61021b61339a565b610223613cfb565b1633811461029557807fffffffffffffffffffffffff0000000000000000000000000000000000000000600054161760005573ffffffffffffffffffffffffffffffffffffffff600154167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278600080a3005b7fdad89dca0000000000000000000000000000000000000000000000000000000060005260046000fd5b600080fd5b346102bf5760206003193601126102bf5760206102e76102e26133bd565b613a43565b604051908152f35b346102bf5760206003193601126102bf5760043580156104805773ffffffffffffffffffffffffffffffffffffffff61032860006139a2565b1633036104525760008052600c6020527f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e9547f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e89060a01c60ff161561043d5761039282825461375a565b90555b6104086040517f23b872dd000000000000000000000000000000000000000000000000000000006020820152336024820152306044820152826064820152606481526103e26084826132c0565b7f0000000000000000000000000000000000000000000000000000000000000000614296565b604051906000825260208201527f569a440e6842b5e5a7ac02286311855f5a0b81b9390909e552e82aaf02c9e9bf60403392a2005b5061044a81600a5461375a565b600a55610395565b7f8e4a23d6000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b7fa90c0d190000000000000000000000000000000000000000000000000000000060005260046000fd5b346102bf576104b83661346a565b9190926104c3613cfb565b6000905b828210610be65750505060009063ffffffff4216907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee184360301925b81811015610be4576000918160051b86013585811215610be05786019061012082360312610be05760405195610538876132a4565b823567ffffffffffffffff81168103610bdc578752602083013567ffffffffffffffff8111610bdc5783019536601f88011215610bdc5786359661057b8861369b565b97610589604051998a6132c0565b8089526020808a019160051b83010190368211610bd85760208301905b828210610ba5575050505060208801968752604084013567ffffffffffffffff8111610ba1576105d99036908601613a28565b92604089019384526106036105f1366060880161350a565b9560608b0196875260c036910161350a565b9660808a01978852610615865161413b565b61061f885161413b565b84515115610b795761063b67ffffffffffffffff8b5116614ac1565b15610b425767ffffffffffffffff8a5116815260076020526040812061077b87516fffffffffffffffffffffffffffffffff604082015116906107366fffffffffffffffffffffffffffffffff602083015116915115158360806040516106a1816132a4565b858152602081018c905260408101849052606081018690520152855474ff000000000000000000000000000000000000000091151560a01b919091167fffffffffffffffffffffff0000000000000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff84161773ffffffff0000000000000000000000000000000060808b901b1617178555565b60809190911b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff91909116176001830155565b6108a189516fffffffffffffffffffffffffffffffff6040820151169061085c6fffffffffffffffffffffffffffffffff602083015116915115158360806040516107c5816132a4565b858152602081018c9052604081018490526060810186905201526002860180547fffffffffffffffffffffff000000000000000000000000000000000000000000166fffffffffffffffffffffffffffffffff85161773ffffffff0000000000000000000000000000000060808c901b161791151560a01b74ff000000000000000000000000000000000000000016919091179055565b60809190911b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff91909116176003830155565b6004865191019080519067ffffffffffffffff8211610b15576108c4835461379b565b601f8111610ada575b50602090601f8311600114610a3b5761091b9291859183610a30575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b90555b88518051821015610953579061094d6001926109468367ffffffffffffffff8f511692613787565b5190613d46565b0161091e565b5050977f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2939199975095610a2167ffffffffffffffff60019796949851169251935191516109ed6109b86040519687968752610100602088015261010087019061333b565b9360408601906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b60a08401906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b0390a101939193929092610503565b015190508f806108e9565b83855281852091907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08416865b818110610ac25750908460019594939210610a8b575b505050811b01905561091e565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558e8080610a7e565b92936020600181928786015181550195019301610a68565b610b059084865260208620601f850160051c81019160208610610b0b575b601f0160051c01906139fe565b8e6108cd565b9091508190610af8565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60249067ffffffffffffffff8b51167f1d5ad3c5000000000000000000000000000000000000000000000000000000008252600452fd5b807f8579befe0000000000000000000000000000000000000000000000000000000060049252fd5b8680fd5b813567ffffffffffffffff8111610bd457602091610bc98392833691890101613a28565b8152019101906105a6565b8a80fd5b8880fd5b8580fd5b8380fd5b005b909267ffffffffffffffff610c07610c0286868699979961371b565b6135de565b1692610c1284614802565b15610d6157836000526007602052610c306005604060002001614609565b9260005b8451811015610c6c57600190866000526007602052610c656005604060002001610c5e8389613787565b519061492d565b5001610c34565b5093909491959250806000526007602052600560406000206000815560006001820155600060028201556000600382015560048101610cab815461379b565b9081610d1e575b5050018054906000815581610cfd575b5050907f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599166020600193604051908152a10190919392936104c7565b6000526020600020908101905b81811015610cc25760008155600101610d0a565b81601f60009311600114610d365750555b8880610cb2565b81835260208320610d5191601f01861c8101906001016139fe565b8082528160208120915555610d2f565b837f1e670e4b0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346102bf5760006003193601126102bf5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346102bf5760006003193601126102bf57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102bf5760206003193601126102bf576020610e40610e3b6133bd565b6139a2565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102bf5760e06003193601126102bf57610e776133bd565b60607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126102bf57604051610ead8161326c565b60243580151581036102bf5781526044356fffffffffffffffffffffffffffffffff811681036102bf5760208201526064356fffffffffffffffffffffffffffffffff811681036102bf57604082015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c3601126102bf5760405190610f348261326c565b60843580151581036102bf57825260a4356fffffffffffffffffffffffffffffffff811681036102bf57602083015260c4356fffffffffffffffffffffffffffffffff811681036102bf57604083015273ffffffffffffffffffffffffffffffffffffffff6009541633141580610fb3575b61045257610be492613f86565b5073ffffffffffffffffffffffffffffffffffffffff60015416331415610fa6565b346102bf5760406003193601126102bf57610fee6133bd565b60243580156104805773ffffffffffffffffffffffffffffffffffffffff611015836139a2565b1633036104525767ffffffffffffffff8216600052600c602052604060002060ff600182015460a01c168060001461112a5781545b8084116110f85750916110de917f58fca2457646a9f47422ab9eb9bff90cef88cd8b8725ab52b1d17baa392d784e936000146110e35761108b8282546135f3565b90555b6110b981337f0000000000000000000000000000000000000000000000000000000000000000613c99565b6040519182913395836020909392919367ffffffffffffffff60408201951681520152565b0390a2005b506110f081600a546135f3565b600a5561108e565b83907fa17e11d50000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b600a5461104a565b346102bf5760206003193601126102bf5767ffffffffffffffff6111546133bd565b61115c6138ef565b501660005260076020526111d761117e611179604060002061391a565b6140b6565b6040519182918291909160806fffffffffffffffffffffffffffffffff8160a084019582815116855263ffffffff6020820151166020860152604081015115156040860152826060820151166060860152015116910152565b0390f35b346102bf5760006003193601126102bf576040516005548082528160208101600560005260206000209260005b8181106112f257505061121d925003826132c0565b80519061124261122c8361369b565b9261123a60405194856132c0565b80845261369b565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060208401920136833760005b81518110156112a2578067ffffffffffffffff61128f60019385613787565b511661129b8287613787565b5201611270565b5050906040519182916020830190602084525180915260408301919060005b8181106112cf575050500390f35b825167ffffffffffffffff168452859450602093840193909201916001016112c1565b8454835260019485019486945060209093019201611208565b346102bf5760206003193601126102bf5761132461339a565b61132c613cfb565b73ffffffffffffffffffffffffffffffffffffffff81169081156113c957600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000811690931790556040805173ffffffffffffffffffffffffffffffffffffffff93841681529190921660208201527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f168491819081015b0390a1005b7f8579befe0000000000000000000000000000000000000000000000000000000060005260046000fd5b346102bf5760206003193601126102bf576111d76114176114126133bd565b613980565b60405191829160208352602083019061333b565b346102bf5760006003193601126102bf57602073ffffffffffffffffffffffffffffffffffffffff60045416604051908152f35b346102bf5760206003193601126102bf5767ffffffffffffffff6114816133bd565b6114896138ef565b501660005260076020526111d761117e611179600260406000200161391a565b346102bf5760006003193601126102bf576020600a54604051908152f35b346102bf5767ffffffffffffffff6114de366133d4565b9290916114e9613cfb565b1690611502826000526006602052604060002054151590565b156115b95781600052600760205261153360056040600020016115263686856135a7565b602081519101209061492d565b15611572577f52d00ee4d9bd51b40168f2afc5848837288ce258784ad914278791464b3f4d7691926110de6040519283926020845260208401916138b0565b6115b5906040519384937f74f23c7c00000000000000000000000000000000000000000000000000000000855260048501526040602485015260448401916138b0565b0390fd5b507f1e670e4b0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346102bf5760006003193601126102bf5760405160025490818152602081018092600260005260206000209060005b818110611685575050508161162c9103826132c0565b6040519182916020830190602084525180915260408301919060005b818110611656575050500390f35b825173ffffffffffffffffffffffffffffffffffffffff16845285945060209384019390920191600101611648565b8254845260209093019260019283019201611616565b346102bf5760206003193601126102bf5767ffffffffffffffff6116bd6133bd565b1660005260076020526116d66005604060002001614609565b8051907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061171c6117068461369b565b9361171460405195866132c0565b80855261369b565b0160005b8181106117f857505060005b8151811015611774578061174260019284613787565b51600052600860205261175860406000206137ee565b6117628286613787565b5261176d8185613787565b500161172c565b826040518091602082016020835281518091526040830190602060408260051b8601019301916000905b8282106117ad57505050500390f35b919360206117e8827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc06001959799849503018652885161333b565b960192019201859493919261179e565b806060602080938701015201611720565b346102bf5760206003193601126102bf5760043567ffffffffffffffff81116102bf5760a060031982360301126102bf576060602060405161184a81613288565b82815201526084810161185c8161362f565b73ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000000000000000000000000000000000000000000016911603611d5957506024810177ffffffffffffffff000000000000000000000000000000006118c2826135de565b60801b16604051907f2cbc26bb000000000000000000000000000000000000000000000000000000008252600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115611c7157600091611d2a575b50611d00576119516044830161362f565b7f0000000000000000000000000000000000000000000000000000000000000000611caa575b5067ffffffffffffffff61198a826135de565b166119a2816000526006602052604060002054151590565b15611c7d57602073ffffffffffffffffffffffffffffffffffffffff60045416916024604051809481937fa8d87a3b00000000000000000000000000000000000000000000000000000000835260048301525afa908115611c7157600091611c07575b5073ffffffffffffffffffffffffffffffffffffffff163303611bd95761141281611b949367ffffffffffffffff6064611a41611b24966135de565b92013591166000526007602052611a9460406000208273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691614b70565b67ffffffffffffffff611aa6836135de565b16600052600c60205260ff60016040600020015460a01c16600014611bc55767ffffffffffffffff611ad7836135de565b16600052600c6020526040600020611af082825461375a565b90555b6040519081527f9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd6000860203392a26135de565b6111d760405160ff7f000000000000000000000000000000000000000000000000000000000000000016602082015260208152611b626040826132c0565b60405192611b6f84613288565b835260208301908152604051938493602085525160406020860152606085019061333b565b90517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084830301604085015261333b565b611bd181600a5461375a565b600a55611af3565b7f728fe07b000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b6020813d602011611c69575b81611c20602093836132c0565b81010312611c6557519073ffffffffffffffffffffffffffffffffffffffff82168203611c62575073ffffffffffffffffffffffffffffffffffffffff611a05565b80fd5b5080fd5b3d9150611c13565b6040513d6000823e3d90fd5b7fa9902c7e0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff16806000526003602052604060002054611977577fd0d259760000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7f53ad11d80000000000000000000000000000000000000000000000000000000060005260046000fd5b611d4c915060203d602011611d52575b611d4481836132c0565b810190613a81565b83611940565b503d611d3a565b611d7773ffffffffffffffffffffffffffffffffffffffff9161362f565b7f961c9a4f000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b346102bf5760606003193601126102bf5760043567ffffffffffffffff81116102bf57611dd6903690600401613439565b9060243567ffffffffffffffff81116102bf57611df79036906004016134bc565b9060443567ffffffffffffffff81116102bf57611e189036906004016134bc565b73ffffffffffffffffffffffffffffffffffffffff6009541633141580611ed9575b61045257838614801590611ecf575b611ea55760005b868110611e5957005b80611e9f611e6d610c026001948b8b61371b565b611e78838989613777565b611e99611e91611e8986898b613777565b92369061350a565b91369061350a565b91613f86565b01611e50565b7f568efce20000000000000000000000000000000000000000000000000000000060005260046000fd5b5080861415611e49565b5073ffffffffffffffffffffffffffffffffffffffff60015416331415611e3a565b346102bf5760006003193601126102bf57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346102bf5760206003193601126102bf576020611f6a67ffffffffffffffff611f566133bd565b166000526006602052604060002054151590565b6040519015158152f35b346102bf5760206003193601126102bf577f44676b5284b809a22248eba0da87391d79098be38bb03154be88a58bf4d09174602073ffffffffffffffffffffffffffffffffffffffff611fc561339a565b611fcd613cfb565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000006009541617600955604051908152a1005b346102bf5760006003193601126102bf5760005473ffffffffffffffffffffffffffffffffffffffff811633036120a2577fffffffffffffffffffffffff00000000000000000000000000000000000000006001549133828416176001551660005573ffffffffffffffffffffffffffffffffffffffff3391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f02b543c60000000000000000000000000000000000000000000000000000000060005260046000fd5b346102bf5760406003193601126102bf5760043567ffffffffffffffff81116102bf576120fd903690600401613439565b6024359167ffffffffffffffff83116102bf57366023840112156102bf5782600401359167ffffffffffffffff83116102bf576024840193602436918560061b0101116102bf5761214c613cfb565b60005b81811061236e5750505060005b81811061216557005b67ffffffffffffffff61217c610c02838587613767565b16158015612339575b6122f4578061227c6121a5602061219f6001958789613767565b0161362f565b8573ffffffffffffffffffffffffffffffffffffffff80866040516121c98161326c565b6000815282602082019616865267ffffffffffffffff6121f4610c028a8d6040860199878b52613767565b16600052600c60205260406000209051815501935116167fffffffffffffffffffffffff00000000000000000000000000000000000000008354161782555115157fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff0000000000000000000000000000000000000000835492151560a01b169116179055565b7f180c6940bd64ba8f75679203ca32f8be2f629477a3307b190656e4b14dd5ddeb6122ab610c02838688613767565b6122bb602061219f85888a613767565b6040805167ffffffffffffffff93909316835273ffffffffffffffffffffffffffffffffffffffff91909116602083015290a10161215c565b610c029061230b9267ffffffffffffffff94613767565b7fd9a9cd68000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b5067ffffffffffffffff612351610c02838587613767565b16600052600c60205260ff60016040600020015460a01c16612185565b67ffffffffffffffff612385610c0283858761371b565b16600052600c60205260ff60016040600020015460a01c1615612457578067ffffffffffffffff6123bc610c02600194868861371b565b16600052600c6020527f7b5efb3f8090c5cfd24e170b667d0e2b6fdc3db6540d75b86d5b6655ba00eb936040600020546123f881600a5461375a565b600a5567ffffffffffffffff612412610c0285888a61371b565b16600052600c602052600084604082208281550155612435610c0284878961371b565b6040805167ffffffffffffffff9290921682526020820192909252a10161214f565b610c029061246e9267ffffffffffffffff9461371b565b7f46f5f12b000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b346102bf5760006003193601126102bf57602073ffffffffffffffffffffffffffffffffffffffff60095416604051908152f35b346102bf5760206003193601126102bf577f66b1c1bdec8b60a3442bb25b5b6cd6fff3d0eceb6f5390be8e2f82a8ad39b23473ffffffffffffffffffffffffffffffffffffffff61251f61339a565b612527613cfb565b6113c4600b54918381167fffffffffffffffffffffffff0000000000000000000000000000000000000000841617600b55604051938493168390929173ffffffffffffffffffffffffffffffffffffffff60209181604085019616845216910152565b346102bf5760406003193601126102bf576125a36133bd565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036102bf5767ffffffffffffffff906125d6613cfb565b169081600052600c602052600160406000200190815460ff8160a01c16156126785782547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283169081179093556040805191909216815260208101929092527f01efd4cd7dd64263689551000d4359d6559c839f39b773b1df3fd19ff060cf5f9190819081016110de565b837f46f5f12b0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346102bf576126b4366133d4565b6126bf929192613cfb565b67ffffffffffffffff82166126e1816000526006602052604060002054151590565b156126fc5750610be4926126f69136916135a7565b90613d46565b7f1e670e4b0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346102bf5761275161275961273d3661346a565b949161274a939193613cfb565b36916136b3565b9236916136b3565b7f0000000000000000000000000000000000000000000000000000000000000000156128795760005b82518110156127f5578073ffffffffffffffffffffffffffffffffffffffff6127ad60019386613787565b51166127b88161466c565b6127c4575b5001612782565b60207f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf756691604051908152a1846127bd565b5060005b8151811015610be4578073ffffffffffffffffffffffffffffffffffffffff61282460019385613787565b511680156128735761283581614a61565b612842575b505b016127f9565b60207f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d891604051908152a18361283a565b5061283c565b7f35f4a7b30000000000000000000000000000000000000000000000000000000060005260046000fd5b346102bf576020611f6a6128b6366133d4565b91613650565b346102bf5760006003193601126102bf57602073ffffffffffffffffffffffffffffffffffffffff600b5416604051908152f35b346102bf5760206003193601126102bf5760043567ffffffffffffffff81116102bf578060040161010060031983360301126102bf57600060405161293481613221565b52608482016129428161362f565b73ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000000000000000000000000000000000000000000016911603611d595750602482019177ffffffffffffffff000000000000000000000000000000006129a9846135de565b60801b16604051907f2cbc26bb000000000000000000000000000000000000000000000000000000008252600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115611c7157600091612d08575b50611d0057612a35836135de565b67ffffffffffffffff8116612a57816000526006602052604060002054151590565b15611c7d5750600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff93909316918301919091523360248301526020908290604490829073ffffffffffffffffffffffffffffffffffffffff165afa908115611c7157600091612ce9575b5015611bd957612ae1836135de565b612af360a48301916128b68386613556565b15612ca2575067ffffffffffffffff612b98612b92612b11866135de565b83606486013591166000526007602052612b8c612b87612b80600260406000200198612b767f00000000000000000000000000000000000000000000000000000000000000009a8673ffffffffffffffffffffffffffffffffffffffff8d1691614b70565b60c4890190613556565b36916135a7565b613a99565b90613b8c565b946135de565b16600052600c602052604060002060ff600182015460a01c1680600014612c9a5781545b808611612c685760208673ffffffffffffffffffffffffffffffffffffffff612c1188612c0c8460448b8b8b15612c5357612bf88482546135f3565b90555b0192612c068461362f565b90613c99565b61362f565b166040518281527f2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52843392a380604051612c4a81613221565b52604051908152f35b50612c6083600a546135f3565b600a55612bfb565b85907fa17e11d50000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b600a54612bbc565b612cac9083613556565b6115b56040519283927f24eb47e50000000000000000000000000000000000000000000000000000000084526020600485015260248401916138b0565b612d02915060203d602011611d5257611d4481836132c0565b84612ad2565b612d21915060203d602011611d5257611d4481836132c0565b84612a27565b346102bf5760206003193601126102bf5767ffffffffffffffff612d496133bd565b16600052600c602052602060ff60016040600020015460a01c166040519015158152f35b346102bf5760406003193601126102bf57612d866133bd565b60243567ffffffffffffffff82168015612e7a5781156104805773ffffffffffffffffffffffffffffffffffffffff612dbe846139a2565b163303610452577f569a440e6842b5e5a7ac02286311855f5a0b81b9390909e552e82aaf02c9e9bf916110de91600052600c602052604060002060ff600182015460a01c16600014612e6557612e1582825461375a565b90555b6110b96040517f23b872dd000000000000000000000000000000000000000000000000000000006020820152336024820152306044820152826064820152606481526103e26084826132c0565b50612e7281600a5461375a565b600a55612e18565b7fd9a9cd6800000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b346102bf5760006003193601126102bf57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102bf5760206003193601126102bf576020612f0261339a565b73ffffffffffffffffffffffffffffffffffffffff807f0000000000000000000000000000000000000000000000000000000000000000169116146040519015158152f35b346102bf5760006003193601126102bf57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102bf5760006003193601126102bf576111d7604051612fba6060826132c0565b602481527f53696c6f65644c6f636b52656c65617365546f6b656e506f6f6c20312e362e3060208201527f2d64657600000000000000000000000000000000000000000000000000000000604082015260405191829160208352602083019061333b565b346102bf5760206003193601126102bf5760043580156104805773ffffffffffffffffffffffffffffffffffffffff61305760006139a2565b1633036104525760008052600c6020527f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e9547f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e89060a01c60ff16801561314a5781545b8084116110f8575015613135576130d28282546135f3565b90555b61310081337f0000000000000000000000000000000000000000000000000000000000000000613c99565b604051906000825260208201527f58fca2457646a9f47422ab9eb9bff90cef88cd8b8725ab52b1d17baa392d784e60403392a2005b5061314281600a546135f3565b600a556130d5565b600a546130ba565b346102bf5760206003193601126102bf57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102bf57817faff2afbf00000000000000000000000000000000000000000000000000000000602093149081156131f7575b81156131cd575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836131c6565b7f0e64dd2900000000000000000000000000000000000000000000000000000000811491506131bf565b6020810190811067ffffffffffffffff82111761323d57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff82111761323d57604052565b6040810190811067ffffffffffffffff82111761323d57604052565b60a0810190811067ffffffffffffffff82111761323d57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761323d57604052565b67ffffffffffffffff811161323d57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b919082519283825260005b8481106133855750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b80602080928401015182828601015201613346565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036102bf57565b6004359067ffffffffffffffff821682036102bf57565b60406003198201126102bf5760043567ffffffffffffffff811681036102bf579160243567ffffffffffffffff81116102bf57826023820112156102bf5780600401359267ffffffffffffffff84116102bf57602484830101116102bf576024019190565b9181601f840112156102bf5782359167ffffffffffffffff83116102bf576020808501948460051b0101116102bf57565b60406003198201126102bf5760043567ffffffffffffffff81116102bf578161349591600401613439565b929092916024359067ffffffffffffffff82116102bf576134b891600401613439565b9091565b9181601f840112156102bf5782359167ffffffffffffffff83116102bf57602080850194606085020101116102bf57565b35906fffffffffffffffffffffffffffffffff821682036102bf57565b91908260609103126102bf576040516135228161326c565b809280359081151582036102bf5760406135519181938552613546602082016134ed565b6020860152016134ed565b910152565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102bf570180359067ffffffffffffffff82116102bf576020019181360383136102bf57565b9291926135b382613301565b916135c160405193846132c0565b8294818452818301116102bf578281602093846000960137010152565b3567ffffffffffffffff811681036102bf5790565b9190820391821161360057565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b3573ffffffffffffffffffffffffffffffffffffffff811681036102bf5790565b613698929167ffffffffffffffff61367b9216600052600760205260056040600020019236916135a7565b602081519101209060019160005201602052604060002054151590565b90565b67ffffffffffffffff811161323d5760051b60200190565b92916136be8261369b565b936136cc60405195866132c0565b602085848152019260051b81019182116102bf57915b8183106136ee57505050565b823573ffffffffffffffffffffffffffffffffffffffff811681036102bf578152602092830192016136e2565b919081101561372b5760051b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190820180921161360057565b919081101561372b5760061b0190565b919081101561372b576060020190565b805182101561372b5760209160051b010190565b90600182811c921680156137e4575b60208310146137b557565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f16916137aa565b90604051918260008254926138028461379b565b80845293600181169081156138705750600114613829575b50613827925003836132c0565b565b90506000929192526020600020906000915b818310613854575050906020613827928201013861381a565b602091935080600191548385890101520191019091849261383b565b602093506138279592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013861381a565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b604051906138fc826132a4565b60006080838281528260208201528260408201528260608201520152565b90604051613927816132a4565b60806001829460ff81546fffffffffffffffffffffffffffffffff8116865263ffffffff81861c16602087015260a01c161515604085015201546fffffffffffffffffffffffffffffffff81166060840152811c910152565b67ffffffffffffffff16600052600760205261369860046040600020016137ee565b67ffffffffffffffff16600052600c60205260016040600020015460ff8160a01c166139e5575073ffffffffffffffffffffffffffffffffffffffff600b541690565b73ffffffffffffffffffffffffffffffffffffffff1690565b818110613a09575050565b600081556001016139fe565b8181029291811591840414171561360057565b9080601f830112156102bf57816020613698933591016135a7565b67ffffffffffffffff1680600052600c60205260ff60016040600020015460a01c16613a705750600a5490565b600052600c60205260406000205490565b908160209103126102bf575180151581036102bf5790565b80518015613b0857602003613aca576020818051810103126102bf5760208101519060ff8211613aca575060ff1690565b6115b5906040519182917f953576f700000000000000000000000000000000000000000000000000000000835260206004840152602483019061333b565b50507f000000000000000000000000000000000000000000000000000000000000000090565b9060ff8091169116039060ff821161360057565b60ff16604d811161360057600a0a90565b8115613b5d570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b907f00000000000000000000000000000000000000000000000000000000000000009060ff82169060ff811692828414613c9257828411613c685790613bd191613b2e565b91604d60ff8416118015613c2f575b613bf957505090613bf361369892613b42565b90613a15565b9091507fa9cb113d0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b50613c3983613b42565b8015613b5d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048411613be0565b613c7191613b2e565b91604d60ff841611613bf957505090613c8c61369892613b42565b90613b53565b5050505090565b6138279273ffffffffffffffffffffffffffffffffffffffff604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252613cf66064836132c0565b614296565b73ffffffffffffffffffffffffffffffffffffffff600154163303613d1c57565b7f2b5c74de0000000000000000000000000000000000000000000000000000000060005260046000fd5b908051156113c95767ffffffffffffffff81516020830120921691826000526007602052613d7b816005604060002001614b1b565b15613f425760005260086020526040600020815167ffffffffffffffff811161323d57613da8825461379b565b601f8111613f10575b506020601f8211600114613e4a5791613e24827f7d628c9a1796743d365ab521a8b2a4686e419b3269919dc9145ea2ce853b54ea9593613e3a95600091613e3f575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b905560405191829160208352602083019061333b565b0390a2565b905084015138613df3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169083600052806000209160005b818110613ef8575092613e3a9492600192827f7d628c9a1796743d365ab521a8b2a4686e419b3269919dc9145ea2ce853b54ea989610613ec1575b5050811b019055611417565b8501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690553880613eb5565b9192602060018192868a015181550194019201613e7a565b613f3c90836000526020600020601f840160051c81019160208510610b0b57601f0160051c01906139fe565b38613db1565b50906115b56040519283927f393b8ad2000000000000000000000000000000000000000000000000000000008452600484015260406024840152604483019061333b565b67ffffffffffffffff166000818152600660205260409020549092919015614088579161408560e09261405185613fdd7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b9761413b565b846000526007602052613ff48160406000206143d6565b613ffd8361413b565b8460005260076020526140178360026040600020016143d6565b60405194855260208501906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b60808301906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565ba1565b827f1e670e4b0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b6140be6138ef565b506fffffffffffffffffffffffffffffffff6060820151166fffffffffffffffffffffffffffffffff808351169161411b602085019361411561410863ffffffff875116426135f3565b8560808901511690613a15565b9061375a565b8082101561413457505b16825263ffffffff4216905290565b9050614125565b8051156141ef576fffffffffffffffffffffffffffffffff6040820151166fffffffffffffffffffffffffffffffff6020830151168110908115916141e6575b506141835750565b6064906141e4604051917f8020d12400000000000000000000000000000000000000000000000000000000835260048301906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565bfd5b9050153861417b565b6fffffffffffffffffffffffffffffffff60408201511615801590614277575b6142165750565b6064906141e4604051917fd68af9cc00000000000000000000000000000000000000000000000000000000835260048301906fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b506fffffffffffffffffffffffffffffffff602082015116151561420f565b73ffffffffffffffffffffffffffffffffffffffff6143259116916040926000808551936142c487866132c0565b602085527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564602086015260208151910182855af13d156143ce573d9161430983613301565b92614316875194856132c0565b83523d6000602085013e614e58565b8051908161433257505050565b602080614343938301019101613a81565b1561434b5750565b608490517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b606091614e58565b7f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199161450f606092805461441363ffffffff8260801c16426135f3565b908161454e575b50506fffffffffffffffffffffffffffffffff600181602086015116928281541680851060001461454657508280855b16167fffffffffffffffffffffffffffffffff000000000000000000000000000000008254161781556144c38651151582907fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff0000000000000000000000000000000000000000835492151560a01b169116179055565b60408601517fffffffffffffffffffffffffffffffff0000000000000000000000000000000060809190911b16939092166fffffffffffffffffffffffffffffffff1692909217910155565b61408560405180926fffffffffffffffffffffffffffffffff60408092805115158552826020820151166020860152015116910152565b83809161444a565b6fffffffffffffffffffffffffffffffff9161458383928361457c6001880154948286169560801c90613a15565b911661375a565b8082101561460257505b83547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff9290911692909216167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116174260801b73ffffffff0000000000000000000000000000000016178155388061441a565b905061458d565b906040519182815491828252602082019060005260206000209260005b81811061463b575050613827925003836132c0565b8454835260019485019487945060209093019201614626565b805482101561372b5760005260206000200190600090565b60008181526003602052604090205480156147fb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811161360057600254907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019182116136005781810361478c575b505050600254801561475d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161471a816002614654565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055600255600052600360205260006040812055600190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6147e361479d6147ae936002614654565b90549060031b1c9283926002614654565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b905560005260036020526040600020553880806146e1565b5050600090565b60008181526006602052604090205480156147fb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811161360057600554907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211613600578181036148f3575b505050600554801561475d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff016148b0816005614654565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055600555600052600660205260006040812055600190565b6149156149046147ae936005614654565b90549060031b1c9283926005614654565b90556000526006602052604060002055388080614877565b9060018201918160005282602052604060002054801515600014614a58577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818111613600578254907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820191821161360057818103614a21575b5050508054801561475d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01906149e28282614654565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b191690555560005260205260006040812055600190565b614a41614a316147ae9386614654565b90549060031b1c92839286614654565b9055600052836020526040600020553880806149aa565b50505050600090565b80600052600360205260406000205415600014614abb576002546801000000000000000081101561323d57614aa26147ae8260018594016002556002614654565b9055600254906000526003602052604060002055600190565b50600090565b80600052600660205260406000205415600014614abb576005546801000000000000000081101561323d57614b026147ae8260018594016005556005614654565b9055600554906000526006602052604060002055600190565b60008281526001820160205260409020546147fb578054906801000000000000000082101561323d5782614b596147ae846001809601855584614654565b905580549260005201602052604060002055600190565b929192805460ff8160a01c16158015614e50575b614e49576fffffffffffffffffffffffffffffffff81169060018301908154614bc963ffffffff6fffffffffffffffffffffffffffffffff83169360801c16426135f3565b9081614dab575b5050848110614d295750838210614c5857507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a939450906fffffffffffffffffffffffffffffffff80614c2685602096956135f3565b16167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055604051908152a1565b819450614c6a92505460801c926135f3565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019080821161360057614cb8614cbd9273ffffffffffffffffffffffffffffffffffffffff9461375a565b613b53565b9216918215614cf9577fd0c8d23a0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b7f15279c080000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b8473ffffffffffffffffffffffffffffffffffffffff8816918215614d7b577f1a76572a0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b7ff94ebcd10000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b828592939511614e1f57614dc6926141159160801c90613a15565b80831015614e1a5750815b83547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff164260801b73ffffffff0000000000000000000000000000000016178455913880614bd0565b614dd1565b7f9725942a0000000000000000000000000000000000000000000000000000000060005260046000fd5b5050509050565b508215614b84565b91929015614ed35750815115614e6c575090565b3b15614e755790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015614ee65750805190602001fd5b6115b5906040519182917f08c379a000000000000000000000000000000000000000000000000000000000835260206004840152602483019061333b56fea164736f6c634300081a000a", +} + +var SiloedLockReleaseTokenPoolABI = SiloedLockReleaseTokenPoolMetaData.ABI + +var SiloedLockReleaseTokenPoolBin = SiloedLockReleaseTokenPoolMetaData.Bin + +func DeploySiloedLockReleaseTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, localTokenDecimals uint8, allowlist []common.Address, rmnProxy common.Address, router common.Address) (common.Address, *types.Transaction, *SiloedLockReleaseTokenPool, error) { + parsed, err := SiloedLockReleaseTokenPoolMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SiloedLockReleaseTokenPoolBin), backend, token, localTokenDecimals, allowlist, rmnProxy, router) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &SiloedLockReleaseTokenPool{address: address, abi: *parsed, SiloedLockReleaseTokenPoolCaller: SiloedLockReleaseTokenPoolCaller{contract: contract}, SiloedLockReleaseTokenPoolTransactor: SiloedLockReleaseTokenPoolTransactor{contract: contract}, SiloedLockReleaseTokenPoolFilterer: SiloedLockReleaseTokenPoolFilterer{contract: contract}}, nil +} + +type SiloedLockReleaseTokenPool struct { + address common.Address + abi abi.ABI + SiloedLockReleaseTokenPoolCaller + SiloedLockReleaseTokenPoolTransactor + SiloedLockReleaseTokenPoolFilterer +} + +type SiloedLockReleaseTokenPoolCaller struct { + contract *bind.BoundContract +} + +type SiloedLockReleaseTokenPoolTransactor struct { + contract *bind.BoundContract +} + +type SiloedLockReleaseTokenPoolFilterer struct { + contract *bind.BoundContract +} + +type SiloedLockReleaseTokenPoolSession struct { + Contract *SiloedLockReleaseTokenPool + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type SiloedLockReleaseTokenPoolCallerSession struct { + Contract *SiloedLockReleaseTokenPoolCaller + CallOpts bind.CallOpts +} + +type SiloedLockReleaseTokenPoolTransactorSession struct { + Contract *SiloedLockReleaseTokenPoolTransactor + TransactOpts bind.TransactOpts +} + +type SiloedLockReleaseTokenPoolRaw struct { + Contract *SiloedLockReleaseTokenPool +} + +type SiloedLockReleaseTokenPoolCallerRaw struct { + Contract *SiloedLockReleaseTokenPoolCaller +} + +type SiloedLockReleaseTokenPoolTransactorRaw struct { + Contract *SiloedLockReleaseTokenPoolTransactor +} + +func NewSiloedLockReleaseTokenPool(address common.Address, backend bind.ContractBackend) (*SiloedLockReleaseTokenPool, error) { + abi, err := abi.JSON(strings.NewReader(SiloedLockReleaseTokenPoolABI)) + if err != nil { + return nil, err + } + contract, err := bindSiloedLockReleaseTokenPool(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPool{address: address, abi: abi, SiloedLockReleaseTokenPoolCaller: SiloedLockReleaseTokenPoolCaller{contract: contract}, SiloedLockReleaseTokenPoolTransactor: SiloedLockReleaseTokenPoolTransactor{contract: contract}, SiloedLockReleaseTokenPoolFilterer: SiloedLockReleaseTokenPoolFilterer{contract: contract}}, nil +} + +func NewSiloedLockReleaseTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*SiloedLockReleaseTokenPoolCaller, error) { + contract, err := bindSiloedLockReleaseTokenPool(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolCaller{contract: contract}, nil +} + +func NewSiloedLockReleaseTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*SiloedLockReleaseTokenPoolTransactor, error) { + contract, err := bindSiloedLockReleaseTokenPool(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolTransactor{contract: contract}, nil +} + +func NewSiloedLockReleaseTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*SiloedLockReleaseTokenPoolFilterer, error) { + contract, err := bindSiloedLockReleaseTokenPool(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolFilterer{contract: contract}, nil +} + +func bindSiloedLockReleaseTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SiloedLockReleaseTokenPoolMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SiloedLockReleaseTokenPool.Contract.SiloedLockReleaseTokenPoolCaller.contract.Call(opts, result, method, params...) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SiloedLockReleaseTokenPoolTransactor.contract.Transfer(opts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SiloedLockReleaseTokenPoolTransactor.contract.Transact(opts, method, params...) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SiloedLockReleaseTokenPool.Contract.contract.Call(opts, result, method, params...) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.contract.Transfer(opts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.contract.Transact(opts, method, params...) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getAllowList") + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetAllowList() ([]common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetAllowList(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetAllowList() ([]common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetAllowList(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getAllowListEnabled") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetAllowListEnabled() (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.GetAllowListEnabled(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetAllowListEnabled() (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.GetAllowListEnabled(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetAvailableTokens(opts *bind.CallOpts, remoteChainSelector uint64) (*big.Int, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getAvailableTokens", remoteChainSelector) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetAvailableTokens(remoteChainSelector uint64) (*big.Int, error) { + return _SiloedLockReleaseTokenPool.Contract.GetAvailableTokens(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetAvailableTokens(remoteChainSelector uint64) (*big.Int, error) { + return _SiloedLockReleaseTokenPool.Contract.GetAvailableTokens(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector) + + if err != nil { + return *new(RateLimiterTokenBucket), err + } + + out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + return _SiloedLockReleaseTokenPool.Contract.GetCurrentInboundRateLimiterState(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + return _SiloedLockReleaseTokenPool.Contract.GetCurrentInboundRateLimiterState(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector) + + if err != nil { + return *new(RateLimiterTokenBucket), err + } + + out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + return _SiloedLockReleaseTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) { + return _SiloedLockReleaseTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getRateLimitAdmin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetRateLimitAdmin() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRateLimitAdmin(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetRateLimitAdmin() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRateLimitAdmin(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetRebalancer(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getRebalancer") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetRebalancer() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRebalancer(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetRebalancer() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRebalancer(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetRemotePools(opts *bind.CallOpts, remoteChainSelector uint64) ([][]byte, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getRemotePools", remoteChainSelector) + + if err != nil { + return *new([][]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][]byte)).(*[][]byte) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetRemotePools(remoteChainSelector uint64) ([][]byte, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRemotePools(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetRemotePools(remoteChainSelector uint64) ([][]byte, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRemotePools(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRemoteToken(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRemoteToken(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getRmnProxy") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetRmnProxy() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRmnProxy(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetRmnProxy() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRmnProxy(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getRouter") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetRouter() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRouter(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetRouter() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetRouter(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetSiloRebalancer(opts *bind.CallOpts, remoteChainSelector uint64) (common.Address, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getSiloRebalancer", remoteChainSelector) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetSiloRebalancer(remoteChainSelector uint64) (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetSiloRebalancer(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetSiloRebalancer(remoteChainSelector uint64) (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetSiloRebalancer(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getSupportedChains") + + if err != nil { + return *new([]uint64), err + } + + out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetSupportedChains() ([]uint64, error) { + return _SiloedLockReleaseTokenPool.Contract.GetSupportedChains(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) { + return _SiloedLockReleaseTokenPool.Contract.GetSupportedChains(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetToken() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetToken(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetToken() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.GetToken(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetTokenDecimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getTokenDecimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetTokenDecimals() (uint8, error) { + return _SiloedLockReleaseTokenPool.Contract.GetTokenDecimals(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetTokenDecimals() (uint8, error) { + return _SiloedLockReleaseTokenPool.Contract.GetTokenDecimals(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) GetUnsiloedLiquidity(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "getUnsiloedLiquidity") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) GetUnsiloedLiquidity() (*big.Int, error) { + return _SiloedLockReleaseTokenPool.Contract.GetUnsiloedLiquidity(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) GetUnsiloedLiquidity() (*big.Int, error) { + return _SiloedLockReleaseTokenPool.Contract.GetUnsiloedLiquidity(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) IsRemotePool(opts *bind.CallOpts, remoteChainSelector uint64, remotePoolAddress []byte) (bool, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "isRemotePool", remoteChainSelector, remotePoolAddress) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) IsRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.IsRemotePool(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector, remotePoolAddress) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) IsRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.IsRemotePool(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector, remotePoolAddress) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) IsSiloed(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "isSiloed", remoteChainSelector) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) IsSiloed(remoteChainSelector uint64) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.IsSiloed(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) IsSiloed(remoteChainSelector uint64) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.IsSiloed(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.IsSupportedChain(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.IsSupportedChain(&_SiloedLockReleaseTokenPool.CallOpts, remoteChainSelector) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "isSupportedToken", token) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) IsSupportedToken(token common.Address) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.IsSupportedToken(&_SiloedLockReleaseTokenPool.CallOpts, token) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) IsSupportedToken(token common.Address) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.IsSupportedToken(&_SiloedLockReleaseTokenPool.CallOpts, token) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) Owner() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.Owner(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) Owner() (common.Address, error) { + return _SiloedLockReleaseTokenPool.Contract.Owner(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.SupportsInterface(&_SiloedLockReleaseTokenPool.CallOpts, interfaceId) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _SiloedLockReleaseTokenPool.Contract.SupportsInterface(&_SiloedLockReleaseTokenPool.CallOpts, interfaceId) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _SiloedLockReleaseTokenPool.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) TypeAndVersion() (string, error) { + return _SiloedLockReleaseTokenPool.Contract.TypeAndVersion(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolCallerSession) TypeAndVersion() (string, error) { + return _SiloedLockReleaseTokenPool.Contract.TypeAndVersion(&_SiloedLockReleaseTokenPool.CallOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "acceptOwnership") +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) AcceptOwnership() (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.AcceptOwnership(&_SiloedLockReleaseTokenPool.TransactOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.AcceptOwnership(&_SiloedLockReleaseTokenPool.TransactOpts) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) AddRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "addRemotePool", remoteChainSelector, remotePoolAddress) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) AddRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.AddRemotePool(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) AddRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.AddRemotePool(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ApplyAllowListUpdates(&_SiloedLockReleaseTokenPool.TransactOpts, removes, adds) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ApplyAllowListUpdates(&_SiloedLockReleaseTokenPool.TransactOpts, removes, adds) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, remoteChainSelectorsToRemove []uint64, chainsToAdd []TokenPoolChainUpdate) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "applyChainUpdates", remoteChainSelectorsToRemove, chainsToAdd) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) ApplyChainUpdates(remoteChainSelectorsToRemove []uint64, chainsToAdd []TokenPoolChainUpdate) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ApplyChainUpdates(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelectorsToRemove, chainsToAdd) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) ApplyChainUpdates(remoteChainSelectorsToRemove []uint64, chainsToAdd []TokenPoolChainUpdate) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ApplyChainUpdates(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelectorsToRemove, chainsToAdd) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "lockOrBurn", lockOrBurnIn) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.LockOrBurn(&_SiloedLockReleaseTokenPool.TransactOpts, lockOrBurnIn) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.LockOrBurn(&_SiloedLockReleaseTokenPool.TransactOpts, lockOrBurnIn) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "provideLiquidity", amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ProvideLiquidity(&_SiloedLockReleaseTokenPool.TransactOpts, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ProvideLiquidity(&_SiloedLockReleaseTokenPool.TransactOpts, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) ProvideSiloedLiquidity(opts *bind.TransactOpts, remoteChainSelector uint64, amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "provideSiloedLiquidity", remoteChainSelector, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) ProvideSiloedLiquidity(remoteChainSelector uint64, amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ProvideSiloedLiquidity(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) ProvideSiloedLiquidity(remoteChainSelector uint64, amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ProvideSiloedLiquidity(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "releaseOrMint", releaseOrMintIn) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ReleaseOrMint(&_SiloedLockReleaseTokenPool.TransactOpts, releaseOrMintIn) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.ReleaseOrMint(&_SiloedLockReleaseTokenPool.TransactOpts, releaseOrMintIn) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) RemoveRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "removeRemotePool", remoteChainSelector, remotePoolAddress) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) RemoveRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.RemoveRemotePool(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) RemoveRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.RemoveRemotePool(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetChainRateLimiterConfig(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetChainRateLimiterConfig(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) SetChainRateLimiterConfigs(opts *bind.TransactOpts, remoteChainSelectors []uint64, outboundConfigs []RateLimiterConfig, inboundConfigs []RateLimiterConfig) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "setChainRateLimiterConfigs", remoteChainSelectors, outboundConfigs, inboundConfigs) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) SetChainRateLimiterConfigs(remoteChainSelectors []uint64, outboundConfigs []RateLimiterConfig, inboundConfigs []RateLimiterConfig) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetChainRateLimiterConfigs(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelectors, outboundConfigs, inboundConfigs) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) SetChainRateLimiterConfigs(remoteChainSelectors []uint64, outboundConfigs []RateLimiterConfig, inboundConfigs []RateLimiterConfig) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetChainRateLimiterConfigs(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelectors, outboundConfigs, inboundConfigs) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "setRateLimitAdmin", rateLimitAdmin) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetRateLimitAdmin(&_SiloedLockReleaseTokenPool.TransactOpts, rateLimitAdmin) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetRateLimitAdmin(&_SiloedLockReleaseTokenPool.TransactOpts, rateLimitAdmin) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) SetRebalancer(opts *bind.TransactOpts, newRebalancer common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "setRebalancer", newRebalancer) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) SetRebalancer(newRebalancer common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetRebalancer(&_SiloedLockReleaseTokenPool.TransactOpts, newRebalancer) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) SetRebalancer(newRebalancer common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetRebalancer(&_SiloedLockReleaseTokenPool.TransactOpts, newRebalancer) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "setRouter", newRouter) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetRouter(&_SiloedLockReleaseTokenPool.TransactOpts, newRouter) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetRouter(&_SiloedLockReleaseTokenPool.TransactOpts, newRouter) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) SetSiloRebalancer(opts *bind.TransactOpts, remoteChainSelector uint64, newRebalancer common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "setSiloRebalancer", remoteChainSelector, newRebalancer) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) SetSiloRebalancer(remoteChainSelector uint64, newRebalancer common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetSiloRebalancer(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, newRebalancer) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) SetSiloRebalancer(remoteChainSelector uint64, newRebalancer common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.SetSiloRebalancer(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, newRebalancer) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "transferOwnership", to) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.TransferOwnership(&_SiloedLockReleaseTokenPool.TransactOpts, to) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.TransferOwnership(&_SiloedLockReleaseTokenPool.TransactOpts, to) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) UpdateSiloDesignations(opts *bind.TransactOpts, removes []uint64, adds []SiloedLockReleaseTokenPoolSiloConfigUpdate) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "updateSiloDesignations", removes, adds) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) UpdateSiloDesignations(removes []uint64, adds []SiloedLockReleaseTokenPoolSiloConfigUpdate) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.UpdateSiloDesignations(&_SiloedLockReleaseTokenPool.TransactOpts, removes, adds) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) UpdateSiloDesignations(removes []uint64, adds []SiloedLockReleaseTokenPoolSiloConfigUpdate) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.UpdateSiloDesignations(&_SiloedLockReleaseTokenPool.TransactOpts, removes, adds) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "withdrawLiquidity", amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.WithdrawLiquidity(&_SiloedLockReleaseTokenPool.TransactOpts, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.WithdrawLiquidity(&_SiloedLockReleaseTokenPool.TransactOpts, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactor) WithdrawSiloedLiquidity(opts *bind.TransactOpts, remoteChainSelector uint64, amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.contract.Transact(opts, "withdrawSiloedLiquidity", remoteChainSelector, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolSession) WithdrawSiloedLiquidity(remoteChainSelector uint64, amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.WithdrawSiloedLiquidity(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, amount) +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolTransactorSession) WithdrawSiloedLiquidity(remoteChainSelector uint64, amount *big.Int) (*types.Transaction, error) { + return _SiloedLockReleaseTokenPool.Contract.WithdrawSiloedLiquidity(&_SiloedLockReleaseTokenPool.TransactOpts, remoteChainSelector, amount) +} + +type SiloedLockReleaseTokenPoolAllowListAddIterator struct { + Event *SiloedLockReleaseTokenPoolAllowListAdd + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolAllowListAddIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolAllowListAdd) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolAllowListAdd) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolAllowListAddIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolAllowListAddIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolAllowListAdd struct { + Sender common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolAllowListAddIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "AllowListAdd") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolAllowListAddIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolAllowListAdd) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "AllowListAdd") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolAllowListAdd) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*SiloedLockReleaseTokenPoolAllowListAdd, error) { + event := new(SiloedLockReleaseTokenPoolAllowListAdd) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolAllowListRemoveIterator struct { + Event *SiloedLockReleaseTokenPoolAllowListRemove + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolAllowListRemoveIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolAllowListRemove) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolAllowListRemove) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolAllowListRemoveIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolAllowListRemoveIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolAllowListRemove struct { + Sender common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolAllowListRemoveIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "AllowListRemove") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolAllowListRemoveIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolAllowListRemove) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "AllowListRemove") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolAllowListRemove) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*SiloedLockReleaseTokenPoolAllowListRemove, error) { + event := new(SiloedLockReleaseTokenPoolAllowListRemove) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolBurnedIterator struct { + Event *SiloedLockReleaseTokenPoolBurned + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolBurnedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolBurned) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolBurned) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolBurnedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolBurnedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolBurned struct { + Sender common.Address + Amount *big.Int + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*SiloedLockReleaseTokenPoolBurnedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "Burned", senderRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolBurnedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolBurned, sender []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "Burned", senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolBurned) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "Burned", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseBurned(log types.Log) (*SiloedLockReleaseTokenPoolBurned, error) { + event := new(SiloedLockReleaseTokenPoolBurned) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "Burned", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolChainAddedIterator struct { + Event *SiloedLockReleaseTokenPoolChainAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolChainAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolChainAddedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolChainAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolChainAdded struct { + RemoteChainSelector uint64 + RemoteToken []byte + OutboundRateLimiterConfig RateLimiterConfig + InboundRateLimiterConfig RateLimiterConfig + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainAddedIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "ChainAdded") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolChainAddedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainAdded) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "ChainAdded") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolChainAdded) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseChainAdded(log types.Log) (*SiloedLockReleaseTokenPoolChainAdded, error) { + event := new(SiloedLockReleaseTokenPoolChainAdded) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolChainConfiguredIterator struct { + Event *SiloedLockReleaseTokenPoolChainConfigured + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolChainConfiguredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainConfigured) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainConfigured) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolChainConfiguredIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolChainConfiguredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolChainConfigured struct { + RemoteChainSelector uint64 + OutboundRateLimiterConfig RateLimiterConfig + InboundRateLimiterConfig RateLimiterConfig + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainConfiguredIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "ChainConfigured") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolChainConfiguredIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainConfigured) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "ChainConfigured") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolChainConfigured) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseChainConfigured(log types.Log) (*SiloedLockReleaseTokenPoolChainConfigured, error) { + event := new(SiloedLockReleaseTokenPoolChainConfigured) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolChainRemovedIterator struct { + Event *SiloedLockReleaseTokenPoolChainRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolChainRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolChainRemovedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolChainRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolChainRemoved struct { + RemoteChainSelector uint64 + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainRemovedIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "ChainRemoved") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolChainRemovedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainRemoved) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "ChainRemoved") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolChainRemoved) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseChainRemoved(log types.Log) (*SiloedLockReleaseTokenPoolChainRemoved, error) { + event := new(SiloedLockReleaseTokenPoolChainRemoved) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolChainSiloedIterator struct { + Event *SiloedLockReleaseTokenPoolChainSiloed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolChainSiloedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainSiloed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainSiloed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolChainSiloedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolChainSiloedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolChainSiloed struct { + RemoteChainSelector uint64 + Rebalancer common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterChainSiloed(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainSiloedIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "ChainSiloed") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolChainSiloedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "ChainSiloed", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchChainSiloed(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainSiloed) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "ChainSiloed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolChainSiloed) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainSiloed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseChainSiloed(log types.Log) (*SiloedLockReleaseTokenPoolChainSiloed, error) { + event := new(SiloedLockReleaseTokenPoolChainSiloed) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainSiloed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolChainUnsiloedIterator struct { + Event *SiloedLockReleaseTokenPoolChainUnsiloed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolChainUnsiloedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainUnsiloed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolChainUnsiloed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolChainUnsiloedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolChainUnsiloedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolChainUnsiloed struct { + RemoteChainSelector uint64 + AmountUnsiloed *big.Int + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterChainUnsiloed(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainUnsiloedIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "ChainUnsiloed") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolChainUnsiloedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "ChainUnsiloed", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchChainUnsiloed(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainUnsiloed) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "ChainUnsiloed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolChainUnsiloed) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainUnsiloed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseChainUnsiloed(log types.Log) (*SiloedLockReleaseTokenPoolChainUnsiloed, error) { + event := new(SiloedLockReleaseTokenPoolChainUnsiloed) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ChainUnsiloed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolConfigChangedIterator struct { + Event *SiloedLockReleaseTokenPoolConfigChanged + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolConfigChangedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolConfigChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolConfigChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolConfigChangedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolConfigChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolConfigChanged struct { + Config RateLimiterConfig + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolConfigChangedIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "ConfigChanged") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolConfigChangedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolConfigChanged) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "ConfigChanged") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolConfigChanged) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseConfigChanged(log types.Log) (*SiloedLockReleaseTokenPoolConfigChanged, error) { + event := new(SiloedLockReleaseTokenPoolConfigChanged) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolLiquidityAddedIterator struct { + Event *SiloedLockReleaseTokenPoolLiquidityAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolLiquidityAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolLiquidityAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolLiquidityAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolLiquidityAddedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolLiquidityAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolLiquidityAdded struct { + RemoteChainSelector uint64 + Provider common.Address + Amount *big.Int + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address) (*SiloedLockReleaseTokenPoolLiquidityAddedIterator, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "LiquidityAdded", providerRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolLiquidityAddedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "LiquidityAdded", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolLiquidityAdded, provider []common.Address) (event.Subscription, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "LiquidityAdded", providerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolLiquidityAdded) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "LiquidityAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseLiquidityAdded(log types.Log) (*SiloedLockReleaseTokenPoolLiquidityAdded, error) { + event := new(SiloedLockReleaseTokenPoolLiquidityAdded) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "LiquidityAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolLiquidityRemovedIterator struct { + Event *SiloedLockReleaseTokenPoolLiquidityRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolLiquidityRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolLiquidityRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolLiquidityRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolLiquidityRemovedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolLiquidityRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolLiquidityRemoved struct { + RemoteChainSelector uint64 + Remover common.Address + Amount *big.Int + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterLiquidityRemoved(opts *bind.FilterOpts, remover []common.Address) (*SiloedLockReleaseTokenPoolLiquidityRemovedIterator, error) { + + var removerRule []interface{} + for _, removerItem := range remover { + removerRule = append(removerRule, removerItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "LiquidityRemoved", removerRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolLiquidityRemovedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "LiquidityRemoved", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolLiquidityRemoved, remover []common.Address) (event.Subscription, error) { + + var removerRule []interface{} + for _, removerItem := range remover { + removerRule = append(removerRule, removerItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "LiquidityRemoved", removerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolLiquidityRemoved) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "LiquidityRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseLiquidityRemoved(log types.Log) (*SiloedLockReleaseTokenPoolLiquidityRemoved, error) { + event := new(SiloedLockReleaseTokenPoolLiquidityRemoved) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "LiquidityRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolLockedIterator struct { + Event *SiloedLockReleaseTokenPoolLocked + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolLockedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolLocked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolLocked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolLockedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolLockedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolLocked struct { + Sender common.Address + Amount *big.Int + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*SiloedLockReleaseTokenPoolLockedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "Locked", senderRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolLockedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolLocked, sender []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "Locked", senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolLocked) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "Locked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseLocked(log types.Log) (*SiloedLockReleaseTokenPoolLocked, error) { + event := new(SiloedLockReleaseTokenPoolLocked) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "Locked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolMintedIterator struct { + Event *SiloedLockReleaseTokenPoolMinted + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolMintedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolMinted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolMinted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolMintedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolMintedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolMinted struct { + Sender common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*SiloedLockReleaseTokenPoolMintedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolMintedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolMinted) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "Minted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseMinted(log types.Log) (*SiloedLockReleaseTokenPoolMinted, error) { + event := new(SiloedLockReleaseTokenPoolMinted) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "Minted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolOwnershipTransferRequestedIterator struct { + Event *SiloedLockReleaseTokenPoolOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*SiloedLockReleaseTokenPoolOwnershipTransferRequestedIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolOwnershipTransferRequestedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolOwnershipTransferRequested) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*SiloedLockReleaseTokenPoolOwnershipTransferRequested, error) { + event := new(SiloedLockReleaseTokenPoolOwnershipTransferRequested) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolOwnershipTransferredIterator struct { + Event *SiloedLockReleaseTokenPoolOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*SiloedLockReleaseTokenPoolOwnershipTransferredIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolOwnershipTransferredIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolOwnershipTransferred) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*SiloedLockReleaseTokenPoolOwnershipTransferred, error) { + event := new(SiloedLockReleaseTokenPoolOwnershipTransferred) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolRateLimitAdminSetIterator struct { + Event *SiloedLockReleaseTokenPoolRateLimitAdminSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolRateLimitAdminSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolRateLimitAdminSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolRateLimitAdminSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolRateLimitAdminSetIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolRateLimitAdminSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolRateLimitAdminSet struct { + RateLimitAdmin common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterRateLimitAdminSet(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolRateLimitAdminSetIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "RateLimitAdminSet") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolRateLimitAdminSetIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "RateLimitAdminSet", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchRateLimitAdminSet(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolRateLimitAdminSet) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "RateLimitAdminSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolRateLimitAdminSet) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "RateLimitAdminSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseRateLimitAdminSet(log types.Log) (*SiloedLockReleaseTokenPoolRateLimitAdminSet, error) { + event := new(SiloedLockReleaseTokenPoolRateLimitAdminSet) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "RateLimitAdminSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolReleasedIterator struct { + Event *SiloedLockReleaseTokenPoolReleased + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolReleasedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolReleased) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolReleased) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolReleasedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolReleasedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolReleased struct { + Sender common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*SiloedLockReleaseTokenPoolReleasedIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolReleasedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolReleased) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "Released", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseReleased(log types.Log) (*SiloedLockReleaseTokenPoolReleased, error) { + event := new(SiloedLockReleaseTokenPoolReleased) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "Released", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolRemotePoolAddedIterator struct { + Event *SiloedLockReleaseTokenPoolRemotePoolAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolRemotePoolAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolRemotePoolAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolRemotePoolAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolRemotePoolAddedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolRemotePoolAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolRemotePoolAdded struct { + RemoteChainSelector uint64 + RemotePoolAddress []byte + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterRemotePoolAdded(opts *bind.FilterOpts, remoteChainSelector []uint64) (*SiloedLockReleaseTokenPoolRemotePoolAddedIterator, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "RemotePoolAdded", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolRemotePoolAddedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "RemotePoolAdded", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchRemotePoolAdded(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolRemotePoolAdded, remoteChainSelector []uint64) (event.Subscription, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "RemotePoolAdded", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolRemotePoolAdded) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "RemotePoolAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseRemotePoolAdded(log types.Log) (*SiloedLockReleaseTokenPoolRemotePoolAdded, error) { + event := new(SiloedLockReleaseTokenPoolRemotePoolAdded) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "RemotePoolAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolRemotePoolRemovedIterator struct { + Event *SiloedLockReleaseTokenPoolRemotePoolRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolRemotePoolRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolRemotePoolRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolRemotePoolRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolRemotePoolRemovedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolRemotePoolRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolRemotePoolRemoved struct { + RemoteChainSelector uint64 + RemotePoolAddress []byte + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterRemotePoolRemoved(opts *bind.FilterOpts, remoteChainSelector []uint64) (*SiloedLockReleaseTokenPoolRemotePoolRemovedIterator, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "RemotePoolRemoved", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolRemotePoolRemovedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "RemotePoolRemoved", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchRemotePoolRemoved(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolRemotePoolRemoved, remoteChainSelector []uint64) (event.Subscription, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "RemotePoolRemoved", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolRemotePoolRemoved) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "RemotePoolRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseRemotePoolRemoved(log types.Log) (*SiloedLockReleaseTokenPoolRemotePoolRemoved, error) { + event := new(SiloedLockReleaseTokenPoolRemotePoolRemoved) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "RemotePoolRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolRouterUpdatedIterator struct { + Event *SiloedLockReleaseTokenPoolRouterUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolRouterUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolRouterUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolRouterUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolRouterUpdatedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolRouterUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolRouterUpdated struct { + OldRouter common.Address + NewRouter common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolRouterUpdatedIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "RouterUpdated") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolRouterUpdatedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolRouterUpdated) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "RouterUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolRouterUpdated) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*SiloedLockReleaseTokenPoolRouterUpdated, error) { + event := new(SiloedLockReleaseTokenPoolRouterUpdated) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolSiloRebalancerSetIterator struct { + Event *SiloedLockReleaseTokenPoolSiloRebalancerSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolSiloRebalancerSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolSiloRebalancerSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolSiloRebalancerSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolSiloRebalancerSetIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolSiloRebalancerSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolSiloRebalancerSet struct { + RemoteChainSelector uint64 + OldRebalancer common.Address + NewRebalancer common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterSiloRebalancerSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*SiloedLockReleaseTokenPoolSiloRebalancerSetIterator, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "SiloRebalancerSet", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolSiloRebalancerSetIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "SiloRebalancerSet", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchSiloRebalancerSet(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolSiloRebalancerSet, remoteChainSelector []uint64) (event.Subscription, error) { + + var remoteChainSelectorRule []interface{} + for _, remoteChainSelectorItem := range remoteChainSelector { + remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem) + } + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "SiloRebalancerSet", remoteChainSelectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolSiloRebalancerSet) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "SiloRebalancerSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseSiloRebalancerSet(log types.Log) (*SiloedLockReleaseTokenPoolSiloRebalancerSet, error) { + event := new(SiloedLockReleaseTokenPoolSiloRebalancerSet) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "SiloRebalancerSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolTokensConsumedIterator struct { + Event *SiloedLockReleaseTokenPoolTokensConsumed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolTokensConsumedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolTokensConsumed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolTokensConsumed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolTokensConsumedIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolTokensConsumedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolTokensConsumed struct { + Tokens *big.Int + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolTokensConsumedIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "TokensConsumed") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolTokensConsumedIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolTokensConsumed) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "TokensConsumed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolTokensConsumed) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseTokensConsumed(log types.Log) (*SiloedLockReleaseTokenPoolTokensConsumed, error) { + event := new(SiloedLockReleaseTokenPoolTokensConsumed) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type SiloedLockReleaseTokenPoolUnsiloedRebalancerSetIterator struct { + Event *SiloedLockReleaseTokenPoolUnsiloedRebalancerSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *SiloedLockReleaseTokenPoolUnsiloedRebalancerSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolUnsiloedRebalancerSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(SiloedLockReleaseTokenPoolUnsiloedRebalancerSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *SiloedLockReleaseTokenPoolUnsiloedRebalancerSetIterator) Error() error { + return it.fail +} + +func (it *SiloedLockReleaseTokenPoolUnsiloedRebalancerSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type SiloedLockReleaseTokenPoolUnsiloedRebalancerSet struct { + OldRebalancer common.Address + NewRebalancer common.Address + Raw types.Log +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) FilterUnsiloedRebalancerSet(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolUnsiloedRebalancerSetIterator, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.FilterLogs(opts, "UnsiloedRebalancerSet") + if err != nil { + return nil, err + } + return &SiloedLockReleaseTokenPoolUnsiloedRebalancerSetIterator{contract: _SiloedLockReleaseTokenPool.contract, event: "UnsiloedRebalancerSet", logs: logs, sub: sub}, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) WatchUnsiloedRebalancerSet(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolUnsiloedRebalancerSet) (event.Subscription, error) { + + logs, sub, err := _SiloedLockReleaseTokenPool.contract.WatchLogs(opts, "UnsiloedRebalancerSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(SiloedLockReleaseTokenPoolUnsiloedRebalancerSet) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "UnsiloedRebalancerSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPoolFilterer) ParseUnsiloedRebalancerSet(log types.Log) (*SiloedLockReleaseTokenPoolUnsiloedRebalancerSet, error) { + event := new(SiloedLockReleaseTokenPoolUnsiloedRebalancerSet) + if err := _SiloedLockReleaseTokenPool.contract.UnpackLog(event, "UnsiloedRebalancerSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _SiloedLockReleaseTokenPool.abi.Events["AllowListAdd"].ID: + return _SiloedLockReleaseTokenPool.ParseAllowListAdd(log) + case _SiloedLockReleaseTokenPool.abi.Events["AllowListRemove"].ID: + return _SiloedLockReleaseTokenPool.ParseAllowListRemove(log) + case _SiloedLockReleaseTokenPool.abi.Events["Burned"].ID: + return _SiloedLockReleaseTokenPool.ParseBurned(log) + case _SiloedLockReleaseTokenPool.abi.Events["ChainAdded"].ID: + return _SiloedLockReleaseTokenPool.ParseChainAdded(log) + case _SiloedLockReleaseTokenPool.abi.Events["ChainConfigured"].ID: + return _SiloedLockReleaseTokenPool.ParseChainConfigured(log) + case _SiloedLockReleaseTokenPool.abi.Events["ChainRemoved"].ID: + return _SiloedLockReleaseTokenPool.ParseChainRemoved(log) + case _SiloedLockReleaseTokenPool.abi.Events["ChainSiloed"].ID: + return _SiloedLockReleaseTokenPool.ParseChainSiloed(log) + case _SiloedLockReleaseTokenPool.abi.Events["ChainUnsiloed"].ID: + return _SiloedLockReleaseTokenPool.ParseChainUnsiloed(log) + case _SiloedLockReleaseTokenPool.abi.Events["ConfigChanged"].ID: + return _SiloedLockReleaseTokenPool.ParseConfigChanged(log) + case _SiloedLockReleaseTokenPool.abi.Events["LiquidityAdded"].ID: + return _SiloedLockReleaseTokenPool.ParseLiquidityAdded(log) + case _SiloedLockReleaseTokenPool.abi.Events["LiquidityRemoved"].ID: + return _SiloedLockReleaseTokenPool.ParseLiquidityRemoved(log) + case _SiloedLockReleaseTokenPool.abi.Events["Locked"].ID: + return _SiloedLockReleaseTokenPool.ParseLocked(log) + case _SiloedLockReleaseTokenPool.abi.Events["Minted"].ID: + return _SiloedLockReleaseTokenPool.ParseMinted(log) + case _SiloedLockReleaseTokenPool.abi.Events["OwnershipTransferRequested"].ID: + return _SiloedLockReleaseTokenPool.ParseOwnershipTransferRequested(log) + case _SiloedLockReleaseTokenPool.abi.Events["OwnershipTransferred"].ID: + return _SiloedLockReleaseTokenPool.ParseOwnershipTransferred(log) + case _SiloedLockReleaseTokenPool.abi.Events["RateLimitAdminSet"].ID: + return _SiloedLockReleaseTokenPool.ParseRateLimitAdminSet(log) + case _SiloedLockReleaseTokenPool.abi.Events["Released"].ID: + return _SiloedLockReleaseTokenPool.ParseReleased(log) + case _SiloedLockReleaseTokenPool.abi.Events["RemotePoolAdded"].ID: + return _SiloedLockReleaseTokenPool.ParseRemotePoolAdded(log) + case _SiloedLockReleaseTokenPool.abi.Events["RemotePoolRemoved"].ID: + return _SiloedLockReleaseTokenPool.ParseRemotePoolRemoved(log) + case _SiloedLockReleaseTokenPool.abi.Events["RouterUpdated"].ID: + return _SiloedLockReleaseTokenPool.ParseRouterUpdated(log) + case _SiloedLockReleaseTokenPool.abi.Events["SiloRebalancerSet"].ID: + return _SiloedLockReleaseTokenPool.ParseSiloRebalancerSet(log) + case _SiloedLockReleaseTokenPool.abi.Events["TokensConsumed"].ID: + return _SiloedLockReleaseTokenPool.ParseTokensConsumed(log) + case _SiloedLockReleaseTokenPool.abi.Events["UnsiloedRebalancerSet"].ID: + return _SiloedLockReleaseTokenPool.ParseUnsiloedRebalancerSet(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (SiloedLockReleaseTokenPoolAllowListAdd) Topic() common.Hash { + return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8") +} + +func (SiloedLockReleaseTokenPoolAllowListRemove) Topic() common.Hash { + return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566") +} + +func (SiloedLockReleaseTokenPoolBurned) Topic() common.Hash { + return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7") +} + +func (SiloedLockReleaseTokenPoolChainAdded) Topic() common.Hash { + return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2") +} + +func (SiloedLockReleaseTokenPoolChainConfigured) Topic() common.Hash { + return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b") +} + +func (SiloedLockReleaseTokenPoolChainRemoved) Topic() common.Hash { + return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916") +} + +func (SiloedLockReleaseTokenPoolChainSiloed) Topic() common.Hash { + return common.HexToHash("0x180c6940bd64ba8f75679203ca32f8be2f629477a3307b190656e4b14dd5ddeb") +} + +func (SiloedLockReleaseTokenPoolChainUnsiloed) Topic() common.Hash { + return common.HexToHash("0x7b5efb3f8090c5cfd24e170b667d0e2b6fdc3db6540d75b86d5b6655ba00eb93") +} + +func (SiloedLockReleaseTokenPoolConfigChanged) Topic() common.Hash { + return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19") +} + +func (SiloedLockReleaseTokenPoolLiquidityAdded) Topic() common.Hash { + return common.HexToHash("0x569a440e6842b5e5a7ac02286311855f5a0b81b9390909e552e82aaf02c9e9bf") +} + +func (SiloedLockReleaseTokenPoolLiquidityRemoved) Topic() common.Hash { + return common.HexToHash("0x58fca2457646a9f47422ab9eb9bff90cef88cd8b8725ab52b1d17baa392d784e") +} + +func (SiloedLockReleaseTokenPoolLocked) Topic() common.Hash { + return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008") +} + +func (SiloedLockReleaseTokenPoolMinted) Topic() common.Hash { + return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0") +} + +func (SiloedLockReleaseTokenPoolOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (SiloedLockReleaseTokenPoolOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (SiloedLockReleaseTokenPoolRateLimitAdminSet) Topic() common.Hash { + return common.HexToHash("0x44676b5284b809a22248eba0da87391d79098be38bb03154be88a58bf4d09174") +} + +func (SiloedLockReleaseTokenPoolReleased) Topic() common.Hash { + return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52") +} + +func (SiloedLockReleaseTokenPoolRemotePoolAdded) Topic() common.Hash { + return common.HexToHash("0x7d628c9a1796743d365ab521a8b2a4686e419b3269919dc9145ea2ce853b54ea") +} + +func (SiloedLockReleaseTokenPoolRemotePoolRemoved) Topic() common.Hash { + return common.HexToHash("0x52d00ee4d9bd51b40168f2afc5848837288ce258784ad914278791464b3f4d76") +} + +func (SiloedLockReleaseTokenPoolRouterUpdated) Topic() common.Hash { + return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684") +} + +func (SiloedLockReleaseTokenPoolSiloRebalancerSet) Topic() common.Hash { + return common.HexToHash("0x01efd4cd7dd64263689551000d4359d6559c839f39b773b1df3fd19ff060cf5f") +} + +func (SiloedLockReleaseTokenPoolTokensConsumed) Topic() common.Hash { + return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a") +} + +func (SiloedLockReleaseTokenPoolUnsiloedRebalancerSet) Topic() common.Hash { + return common.HexToHash("0x66b1c1bdec8b60a3442bb25b5b6cd6fff3d0eceb6f5390be8e2f82a8ad39b234") +} + +func (_SiloedLockReleaseTokenPool *SiloedLockReleaseTokenPool) Address() common.Address { + return _SiloedLockReleaseTokenPool.address +} + +type SiloedLockReleaseTokenPoolInterface interface { + GetAllowList(opts *bind.CallOpts) ([]common.Address, error) + + GetAllowListEnabled(opts *bind.CallOpts) (bool, error) + + GetAvailableTokens(opts *bind.CallOpts, remoteChainSelector uint64) (*big.Int, error) + + GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) + + GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) + + GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error) + + GetRebalancer(opts *bind.CallOpts) (common.Address, error) + + GetRemotePools(opts *bind.CallOpts, remoteChainSelector uint64) ([][]byte, error) + + GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) + + GetRmnProxy(opts *bind.CallOpts) (common.Address, error) + + GetRouter(opts *bind.CallOpts) (common.Address, error) + + GetSiloRebalancer(opts *bind.CallOpts, remoteChainSelector uint64) (common.Address, error) + + GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) + + GetToken(opts *bind.CallOpts) (common.Address, error) + + GetTokenDecimals(opts *bind.CallOpts) (uint8, error) + + GetUnsiloedLiquidity(opts *bind.CallOpts) (*big.Int, error) + + IsRemotePool(opts *bind.CallOpts, remoteChainSelector uint64, remotePoolAddress []byte) (bool, error) + + IsSiloed(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) + + IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) + + IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AddRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) + + ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) + + ApplyChainUpdates(opts *bind.TransactOpts, remoteChainSelectorsToRemove []uint64, chainsToAdd []TokenPoolChainUpdate) (*types.Transaction, error) + + LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) + + ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) + + ProvideSiloedLiquidity(opts *bind.TransactOpts, remoteChainSelector uint64, amount *big.Int) (*types.Transaction, error) + + ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) + + RemoveRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) + + SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) + + SetChainRateLimiterConfigs(opts *bind.TransactOpts, remoteChainSelectors []uint64, outboundConfigs []RateLimiterConfig, inboundConfigs []RateLimiterConfig) (*types.Transaction, error) + + SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error) + + SetRebalancer(opts *bind.TransactOpts, newRebalancer common.Address) (*types.Transaction, error) + + SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) + + SetSiloRebalancer(opts *bind.TransactOpts, remoteChainSelector uint64, newRebalancer common.Address) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + UpdateSiloDesignations(opts *bind.TransactOpts, removes []uint64, adds []SiloedLockReleaseTokenPoolSiloConfigUpdate) (*types.Transaction, error) + + WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) + + WithdrawSiloedLiquidity(opts *bind.TransactOpts, remoteChainSelector uint64, amount *big.Int) (*types.Transaction, error) + + FilterAllowListAdd(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolAllowListAddIterator, error) + + WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolAllowListAdd) (event.Subscription, error) + + ParseAllowListAdd(log types.Log) (*SiloedLockReleaseTokenPoolAllowListAdd, error) + + FilterAllowListRemove(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolAllowListRemoveIterator, error) + + WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolAllowListRemove) (event.Subscription, error) + + ParseAllowListRemove(log types.Log) (*SiloedLockReleaseTokenPoolAllowListRemove, error) + + FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*SiloedLockReleaseTokenPoolBurnedIterator, error) + + WatchBurned(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolBurned, sender []common.Address) (event.Subscription, error) + + ParseBurned(log types.Log) (*SiloedLockReleaseTokenPoolBurned, error) + + FilterChainAdded(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainAddedIterator, error) + + WatchChainAdded(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainAdded) (event.Subscription, error) + + ParseChainAdded(log types.Log) (*SiloedLockReleaseTokenPoolChainAdded, error) + + FilterChainConfigured(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainConfiguredIterator, error) + + WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainConfigured) (event.Subscription, error) + + ParseChainConfigured(log types.Log) (*SiloedLockReleaseTokenPoolChainConfigured, error) + + FilterChainRemoved(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainRemovedIterator, error) + + WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainRemoved) (event.Subscription, error) + + ParseChainRemoved(log types.Log) (*SiloedLockReleaseTokenPoolChainRemoved, error) + + FilterChainSiloed(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainSiloedIterator, error) + + WatchChainSiloed(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainSiloed) (event.Subscription, error) + + ParseChainSiloed(log types.Log) (*SiloedLockReleaseTokenPoolChainSiloed, error) + + FilterChainUnsiloed(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolChainUnsiloedIterator, error) + + WatchChainUnsiloed(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolChainUnsiloed) (event.Subscription, error) + + ParseChainUnsiloed(log types.Log) (*SiloedLockReleaseTokenPoolChainUnsiloed, error) + + FilterConfigChanged(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolConfigChangedIterator, error) + + WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolConfigChanged) (event.Subscription, error) + + ParseConfigChanged(log types.Log) (*SiloedLockReleaseTokenPoolConfigChanged, error) + + FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address) (*SiloedLockReleaseTokenPoolLiquidityAddedIterator, error) + + WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolLiquidityAdded, provider []common.Address) (event.Subscription, error) + + ParseLiquidityAdded(log types.Log) (*SiloedLockReleaseTokenPoolLiquidityAdded, error) + + FilterLiquidityRemoved(opts *bind.FilterOpts, remover []common.Address) (*SiloedLockReleaseTokenPoolLiquidityRemovedIterator, error) + + WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolLiquidityRemoved, remover []common.Address) (event.Subscription, error) + + ParseLiquidityRemoved(log types.Log) (*SiloedLockReleaseTokenPoolLiquidityRemoved, error) + + FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*SiloedLockReleaseTokenPoolLockedIterator, error) + + WatchLocked(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolLocked, sender []common.Address) (event.Subscription, error) + + ParseLocked(log types.Log) (*SiloedLockReleaseTokenPoolLocked, error) + + FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*SiloedLockReleaseTokenPoolMintedIterator, error) + + WatchMinted(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) + + ParseMinted(log types.Log) (*SiloedLockReleaseTokenPoolMinted, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*SiloedLockReleaseTokenPoolOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*SiloedLockReleaseTokenPoolOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*SiloedLockReleaseTokenPoolOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*SiloedLockReleaseTokenPoolOwnershipTransferred, error) + + FilterRateLimitAdminSet(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolRateLimitAdminSetIterator, error) + + WatchRateLimitAdminSet(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolRateLimitAdminSet) (event.Subscription, error) + + ParseRateLimitAdminSet(log types.Log) (*SiloedLockReleaseTokenPoolRateLimitAdminSet, error) + + FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*SiloedLockReleaseTokenPoolReleasedIterator, error) + + WatchReleased(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) + + ParseReleased(log types.Log) (*SiloedLockReleaseTokenPoolReleased, error) + + FilterRemotePoolAdded(opts *bind.FilterOpts, remoteChainSelector []uint64) (*SiloedLockReleaseTokenPoolRemotePoolAddedIterator, error) + + WatchRemotePoolAdded(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolRemotePoolAdded, remoteChainSelector []uint64) (event.Subscription, error) + + ParseRemotePoolAdded(log types.Log) (*SiloedLockReleaseTokenPoolRemotePoolAdded, error) + + FilterRemotePoolRemoved(opts *bind.FilterOpts, remoteChainSelector []uint64) (*SiloedLockReleaseTokenPoolRemotePoolRemovedIterator, error) + + WatchRemotePoolRemoved(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolRemotePoolRemoved, remoteChainSelector []uint64) (event.Subscription, error) + + ParseRemotePoolRemoved(log types.Log) (*SiloedLockReleaseTokenPoolRemotePoolRemoved, error) + + FilterRouterUpdated(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolRouterUpdatedIterator, error) + + WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolRouterUpdated) (event.Subscription, error) + + ParseRouterUpdated(log types.Log) (*SiloedLockReleaseTokenPoolRouterUpdated, error) + + FilterSiloRebalancerSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*SiloedLockReleaseTokenPoolSiloRebalancerSetIterator, error) + + WatchSiloRebalancerSet(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolSiloRebalancerSet, remoteChainSelector []uint64) (event.Subscription, error) + + ParseSiloRebalancerSet(log types.Log) (*SiloedLockReleaseTokenPoolSiloRebalancerSet, error) + + FilterTokensConsumed(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolTokensConsumedIterator, error) + + WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolTokensConsumed) (event.Subscription, error) + + ParseTokensConsumed(log types.Log) (*SiloedLockReleaseTokenPoolTokensConsumed, error) + + FilterUnsiloedRebalancerSet(opts *bind.FilterOpts) (*SiloedLockReleaseTokenPoolUnsiloedRebalancerSetIterator, error) + + WatchUnsiloedRebalancerSet(opts *bind.WatchOpts, sink chan<- *SiloedLockReleaseTokenPoolUnsiloedRebalancerSet) (event.Subscription, error) + + ParseUnsiloedRebalancerSet(log types.Log) (*SiloedLockReleaseTokenPoolUnsiloedRebalancerSet, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 75ad440e0fa..21e24c90be0 100644 --- a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,6 +1,7 @@ GETH_VERSION: 1.14.11 burn_from_mint_token_pool: ../../../contracts/solc/ccip/BurnFromMintTokenPool/BurnFromMintTokenPool.sol/BurnFromMintTokenPool.abi.json ../../../contracts/solc/ccip/BurnFromMintTokenPool/BurnFromMintTokenPool.sol/BurnFromMintTokenPool.bin ae4e15dc926517092d46e108cd5e24863d58e689444ce310bb00c1390f711ba9 burn_mint_token_pool: ../../../contracts/solc/ccip/BurnMintTokenPool/BurnMintTokenPool.sol/BurnMintTokenPool.abi.json ../../../contracts/solc/ccip/BurnMintTokenPool/BurnMintTokenPool.sol/BurnMintTokenPool.bin 7360dc05306d51b247abdf9a3aa8704847b1f4fb91fdb822a2dfc54e1d86cda1 +burn_to_address_mint_token_pool: ../../../contracts/solc/ccip/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.sol/BurnToAddressMintTokenPool.abi.json ../../../contracts/solc/ccip/BurnToAddressMintTokenPool/BurnToAddressMintTokenPool.sol/BurnToAddressMintTokenPool.bin ca4d24535b7c8a9cff9ca0ff96a41b8410b0e055059e45152e3e49a7c40a6656 burn_with_from_mint_token_pool: ../../../contracts/solc/ccip/BurnWithFromMintTokenPool/BurnWithFromMintTokenPool.sol/BurnWithFromMintTokenPool.abi.json ../../../contracts/solc/ccip/BurnWithFromMintTokenPool/BurnWithFromMintTokenPool.sol/BurnWithFromMintTokenPool.bin 66715c303bb2da2b49bba100a788f6471b0f94d255d40f92306e279b909ae33b ccip_encoding_utils: ../../../contracts/solc/ccip/EncodingUtils/EncodingUtils.sol/EncodingUtils.abi.json ../../../contracts/solc/ccip/EncodingUtils/EncodingUtils.sol/EncodingUtils.bin abd960015cec3e4d94a5948d2d66ee915770fe4a744c28a5ff46d23e870baaea ccip_home: ../../../contracts/solc/ccip/CCIPHome/CCIPHome.sol/CCIPHome.abi.json ../../../contracts/solc/ccip/CCIPHome/CCIPHome.sol/CCIPHome.bin 39de1fbc907a2b573e9358e716803bf5ac3b0a2e622d5bc0069ab60daf38949b @@ -27,6 +28,7 @@ rmn_home: ../../../contracts/solc/ccip/RMNHome/RMNHome.sol/RMNHome.abi.json ../. rmn_proxy_contract: ../../../contracts/solc/ccip/RMNProxy/RMNProxy.sol/RMNProxy.abi.json ../../../contracts/solc/ccip/RMNProxy/RMNProxy.sol/RMNProxy.bin 4d06f9e5c6f72daef745e6114faed3bae57ad29758d75de5a4eefcd5f0172328 rmn_remote: ../../../contracts/solc/ccip/RMNRemote/RMNRemote.sol/RMNRemote.abi.json ../../../contracts/solc/ccip/RMNRemote/RMNRemote.sol/RMNRemote.bin 32173df61397fc104bc6bcd9d8e929165ee3911518350dc7f2bb5d1d94875a94 router: ../../../contracts/solc/ccip/Router/Router.sol/Router.abi.json ../../../contracts/solc/ccip/Router/Router.sol/Router.bin 0103ab2fd344179d49f0320d0a47ec8255fe8a401a2f2c8973e8314dc49d2413 +siloed_lock_release_token_pool: ../../../contracts/solc/ccip/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.sol/SiloedLockReleaseTokenPool.abi.json ../../../contracts/solc/ccip/SiloedLockReleaseTokenPool/SiloedLockReleaseTokenPool.sol/SiloedLockReleaseTokenPool.bin 53a592f99d2a47e0b9b012d6f863a0224ba106b687511ff6c67cea160c42fc3a token_admin_registry: ../../../contracts/solc/ccip/TokenAdminRegistry/TokenAdminRegistry.sol/TokenAdminRegistry.abi.json ../../../contracts/solc/ccip/TokenAdminRegistry/TokenAdminRegistry.sol/TokenAdminRegistry.bin 086268b9df56e089a69a96ce3e4fd03a07a00a1c8812ba9504e31930a5c3ff1d token_pool: ../../../contracts/solc/ccip/TokenPool/TokenPool.sol/TokenPool.abi.json ../../../contracts/solc/ccip/TokenPool/TokenPool.sol/TokenPool.bin 6c00ce7b2082f40d5f9b4808eb692a90e81c312b4f5d70d62e4b1ef69a164a9f usdc_reader_tester: ../../../contracts/solc/ccip/USDCReaderTester/USDCReaderTester.sol/USDCReaderTester.abi.json ../../../contracts/solc/ccip/USDCReaderTester/USDCReaderTester.sol/USDCReaderTester.bin 7622b1e42bc9c3933c51607d765d8463796c615155596929e554a58ed68b263d diff --git a/core/gethwrappers/ccip/go_generate.go b/core/gethwrappers/ccip/go_generate.go index 4e4822d9a2e..734789f338f 100644 --- a/core/gethwrappers/ccip/go_generate.go +++ b/core/gethwrappers/ccip/go_generate.go @@ -22,6 +22,8 @@ package ccip //go:generate go run ../generation/wrap.go ccip LockReleaseTokenPool lock_release_token_pool //go:generate go run ../generation/wrap.go ccip TokenPool token_pool //go:generate go run ../generation/wrap.go ccip USDCTokenPool usdc_token_pool +//go:generate go run ../generation/wrap.go ccip SiloedLockReleaseTokenPool siloed_lock_release_token_pool +//go:generate go run ../generation/wrap.go ccip BurnToAddressMintTokenPool burn_to_address_mint_token_pool // Helpers //go:generate go run ../generation/wrap.go ccip MaybeRevertMessageReceiver maybe_revert_message_receiver From 8af9a9097549bfb36a12f1e7e245f0a051dc1dbf Mon Sep 17 00:00:00 2001 From: tt-cll <141346969+tt-cll@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:22:32 -0500 Subject: [PATCH 29/43] save solana pdas in address book (#16135) * pdas in ab * clean up merge * use labels * load config pda from state * lint --- .../changeset/solana/cs_chain_contracts.go | 74 +++++++++++-------- .../solana/cs_chain_contracts_test.go | 7 +- deployment/ccip/changeset/solana_state.go | 60 +++++++++++++-- .../changeset/testhelpers/test_helpers.go | 5 +- 4 files changed, 100 insertions(+), 46 deletions(-) diff --git a/deployment/ccip/changeset/solana/cs_chain_contracts.go b/deployment/ccip/changeset/solana/cs_chain_contracts.go index 59ec483feb4..a5a4bfae663 100644 --- a/deployment/ccip/changeset/solana/cs_chain_contracts.go +++ b/deployment/ccip/changeset/solana/cs_chain_contracts.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strconv" "github.com/gagliardetto/solana-go" @@ -95,9 +96,8 @@ func validateRouterConfig(chain deployment.SolChain, chainState cs.SolCCIPChainS return fmt.Errorf("router not found in existing state, deploy the router first chain %d", chain.Selector) } // addressing errcheck in the next PR - routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) var routerConfigAccount solRouter.Config - err := chain.GetAccountDataBorshInto(context.Background(), routerConfigPDA, &routerConfigAccount) + err := chain.GetAccountDataBorshInto(context.Background(), chainState.RouterConfigPDA, &routerConfigAccount) if err != nil { return fmt.Errorf("router config not found in existing state, initialize the router first %d", chain.Selector) } @@ -146,10 +146,9 @@ func (cfg AddRemoteChainToSolanaConfig) Validate(e deployment.Environment) error if err := commoncs.ValidateOwnershipSolana(e.GetContext(), cfg.MCMS != nil, e.SolChains[chainSel].DeployerKey.PublicKey(), chainState.Timelock, chainState.Router); err != nil { return fmt.Errorf("failed to validate ownership: %w", err) } - routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) var routerConfigAccount solRouter.Config // already validated that router config exists - _ = chain.GetAccountDataBorshInto(context.Background(), routerConfigPDA, &routerConfigAccount) + _ = chain.GetAccountDataBorshInto(context.Background(), chainState.RouterConfigPDA, &routerConfigAccount) for remote := range updates { if _, ok := supportedChains[remote]; !ok { @@ -175,17 +174,22 @@ func AddRemoteChainToSolana(e deployment.Environment, cfg AddRemoteChainToSolana return deployment.ChangesetOutput{}, err } + ab := deployment.NewMemoryAddressBook() for chainSel, updates := range cfg.UpdatesByChain { - _, err := doAddRemoteChainToSolana(e, s, chainSel, updates) + err := doAddRemoteChainToSolana(e, s, chainSel, updates, ab) if err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{AddressBook: ab}, err } } - - return deployment.ChangesetOutput{}, nil + return deployment.ChangesetOutput{AddressBook: ab}, nil } -func doAddRemoteChainToSolana(e deployment.Environment, s cs.CCIPOnChainState, chainSel uint64, updates map[uint64]RemoteChainConfigSolana) (deployment.ChangesetOutput, error) { +func doAddRemoteChainToSolana( + e deployment.Environment, + s cs.CCIPOnChainState, + chainSel uint64, + updates map[uint64]RemoteChainConfigSolana, + ab deployment.AddressBook) error { chain := e.SolChains[chainSel] ccipRouterID := s.SolChains[chainSel].Router @@ -195,11 +199,11 @@ func doAddRemoteChainToSolana(e deployment.Environment, s cs.CCIPOnChainState, c remoteChainFamily, _ := chainsel.GetSelectorFamily(remoteChainSel) switch remoteChainFamily { case chainsel.FamilySolana: - return deployment.ChangesetOutput{}, fmt.Errorf("support for solana chain as remote chain is not implemented yet %d", remoteChainSel) + return fmt.Errorf("support for solana chain as remote chain is not implemented yet %d", remoteChainSel) case chainsel.FamilyEVM: onRampAddress := s.Chains[remoteChainSel].OnRamp.Address().String() if onRampAddress == "" { - return deployment.ChangesetOutput{}, fmt.Errorf("onramp address not found for chain %d", remoteChainSel) + return fmt.Errorf("onramp address not found for chain %d", remoteChainSel) } addressBytes := []byte(onRampAddress) copy(onRampBytes[:], addressBytes) @@ -210,7 +214,6 @@ func doAddRemoteChainToSolana(e deployment.Environment, s cs.CCIPOnChainState, c IsEnabled: update.EnabledAsSource, } // addressing errcheck in the next PR - routerConfigPDA, _, _ := solState.FindConfigPDA(ccipRouterID) destChainStatePDA, _ := solState.FindDestChainStatePDA(remoteChainSel, ccipRouterID) sourceChainStatePDA, _ := solState.FindSourceChainStatePDA(remoteChainSel, ccipRouterID) @@ -220,24 +223,38 @@ func doAddRemoteChainToSolana(e deployment.Environment, s cs.CCIPOnChainState, c update.DestinationConfig, sourceChainStatePDA, destChainStatePDA, - routerConfigPDA, + s.SolChains[chainSel].RouterConfigPDA, chain.DeployerKey.PublicKey(), solana.SystemProgramID, ).ValidateAndBuild() if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err) + return fmt.Errorf("failed to generate instructions: %w", err) } err = chain.Confirm([]solana.Instruction{instruction}) - if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err) + return fmt.Errorf("failed to confirm instructions: %w", err) } e.Logger.Infow("Confirmed instruction", "instruction", instruction) + + tv := deployment.NewTypeAndVersion(cs.RemoteDest, deployment.Version1_0_0) + remoteChainSelStr := strconv.FormatUint(remoteChainSel, 10) + tv.AddLabel(remoteChainSelStr) + err = ab.Save(chainSel, destChainStatePDA.String(), tv) + if err != nil { + return fmt.Errorf("failed to save dest chain state to address book: %w", err) + } + + tv = deployment.NewTypeAndVersion(cs.RemoteSource, deployment.Version1_0_0) + tv.AddLabel(remoteChainSelStr) + err = ab.Save(chainSel, sourceChainStatePDA.String(), tv) + if err != nil { + return fmt.Errorf("failed to save source chain state to address book: %w", err) + } } - return deployment.ChangesetOutput{}, nil + return nil } // SET OCR3 CONFIG @@ -282,10 +299,8 @@ func SetOCR3ConfigSolana(e deployment.Environment, cfg cs.SetOCR3OffRampConfig) // TODO: check if ocr3 has already been set // set, err := isOCR3ConfigSetSolana(e.Logger, e.Chains[remote], state.Chains[remote].OffRamp, args) var instructions []solana.Instruction - ccipRouterID := solChains[remote].Router - // addressing errcheck in the next PR - routerConfigPDA, _, _ := solState.FindConfigPDA(ccipRouterID) - routerStatePDA, _, _ := solState.FindStatePDA(ccipRouterID) + routerConfigPDA := solChains[remote].RouterConfigPDA + routerStatePDA := solChains[remote].RouterStatePDA for _, arg := range args { instruction, err := solRouter.NewSetOcrConfigInstruction( arg.OCRPluginType, @@ -566,7 +581,6 @@ func AddBillingToken(e deployment.Environment, cfg BillingTokenConfig) (deployme // verified tokenprogramID, _ := GetTokenProgramID(cfg.TokenProgramName) - routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) billingConfigPDA, _, _ := solState.FindFeeBillingTokenConfigPDA(tokenPubKey, chainState.Router) // addressing errcheck in the next PR @@ -575,7 +589,7 @@ func AddBillingToken(e deployment.Environment, cfg BillingTokenConfig) (deployme ixConfig, cerr := solRouter.NewAddBillingTokenConfigInstruction( cfg.Config, - routerConfigPDA, + chainState.RouterConfigPDA, billingConfigPDA, tokenprogramID, tokenPubKey, @@ -639,13 +653,12 @@ func AddBillingTokenForRemoteChain(e deployment.Environment, cfg BillingTokenFor tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) // verified remoteBillingPDA, _, _ := solState.FindCcipTokenpoolBillingPDA(cfg.RemoteChainSelector, tokenPubKey, chainState.Router) - routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) ix, err := solRouter.NewSetTokenBillingInstruction( cfg.RemoteChainSelector, tokenPubKey, cfg.Config, - routerConfigPDA, + chainState.RouterConfigPDA, remoteBillingPDA, chain.DeployerKey.PublicKey(), solana.SystemProgramID, @@ -716,7 +729,6 @@ func RegisterTokenAdminRegistry(e deployment.Environment, cfg RegisterTokenAdmin tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey) // verified - routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) var instruction *solRouter.Instruction @@ -728,7 +740,7 @@ func RegisterTokenAdminRegistry(e deployment.Environment, cfg RegisterTokenAdmin instruction, err = solRouter.NewRegisterTokenAdminRegistryViaGetCcipAdminInstruction( tokenPubKey, tokenAdminRegistryAdmin, // admin of the tokenAdminRegistry PDA - routerConfigPDA, + chainState.RouterConfigPDA, tokenAdminRegistryPDA, // this gets created chain.DeployerKey.PublicKey(), // (ccip admin) solana.SystemProgramID, @@ -739,7 +751,7 @@ func RegisterTokenAdminRegistry(e deployment.Environment, cfg RegisterTokenAdmin case ViaOwnerInstruction: // the token mint authority signs and makes itself the authority of the tokenAdminRegistry PDA instruction, err = solRouter.NewRegisterTokenAdminRegistryViaOwnerInstruction( - routerConfigPDA, + chainState.RouterConfigPDA, tokenAdminRegistryPDA, // this gets created tokenPubKey, chain.DeployerKey.PublicKey(), // (token mint authority) becomes the authority of the tokenAdminRegistry PDA @@ -819,7 +831,6 @@ func TransferAdminRoleTokenAdminRegistry(e deployment.Environment, cfg TransferA // verified tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) - routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) currentRegistryAdminPrivateKey := solana.MustPrivateKeyFromBase58(cfg.CurrentRegistryAdminPrivateKey) newRegistryAdminPubKey := solana.MustPublicKeyFromBase58(cfg.NewRegistryAdminPublicKey) @@ -827,7 +838,7 @@ func TransferAdminRoleTokenAdminRegistry(e deployment.Environment, cfg TransferA ix1, err := solRouter.NewTransferAdminRoleTokenAdminRegistryInstruction( tokenPubKey, newRegistryAdminPubKey, - routerConfigPDA, + chainState.RouterConfigPDA, tokenAdminRegistryPDA, currentRegistryAdminPrivateKey.PublicKey(), // as we are assuming this is the default authority for everything in the beginning ).ValidateAndBuild() @@ -892,11 +903,10 @@ func AcceptAdminRoleTokenAdminRegistry(e deployment.Environment, cfg AcceptAdmin // verified tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router) - routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router) ix1, err := solRouter.NewAcceptAdminRoleTokenAdminRegistryInstruction( tokenPubKey, - routerConfigPDA, + chainState.RouterConfigPDA, tokenAdminRegistryPDA, newRegistryAdminPrivateKey.PublicKey(), ).ValidateAndBuild() diff --git a/deployment/ccip/changeset/solana/cs_chain_contracts_test.go b/deployment/ccip/changeset/solana/cs_chain_contracts_test.go index a7b489a5aa4..a8e122d48a7 100644 --- a/deployment/ccip/changeset/solana/cs_chain_contracts_test.go +++ b/deployment/ccip/changeset/solana/cs_chain_contracts_test.go @@ -36,7 +36,7 @@ func TestAddRemoteChain(t *testing.T) { state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) - _, err = commonchangeset.ApplyChangesets(t, tenv.Env, nil, []commonchangeset.ChangesetApplication{ + tenv.Env, err = commonchangeset.ApplyChangesets(t, tenv.Env, nil, []commonchangeset.ChangesetApplication{ { Changeset: commonchangeset.WrapChangeSet(changeset.UpdateOnRampsDestsChangeset), Config: changeset.UpdateOnRampDestsConfig{ @@ -80,16 +80,15 @@ func TestAddRemoteChain(t *testing.T) { state, err = changeset.LoadOnchainStateSolana(tenv.Env) require.NoError(t, err) - var sourceChainStateAccount solRouter.SourceChain - evmSourceChainStatePDA, _ := solState.FindSourceChainStatePDA(evmChain, state.SolChains[solChain].Router) + evmSourceChainStatePDA := state.SolChains[solChain].SourceChainStatePDAs[evmChain] err = tenv.Env.SolChains[solChain].GetAccountDataBorshInto(ctx, evmSourceChainStatePDA, &sourceChainStateAccount) require.NoError(t, err) require.Equal(t, uint64(1), sourceChainStateAccount.State.MinSeqNr) require.True(t, sourceChainStateAccount.Config.IsEnabled) var destChainStateAccount solRouter.DestChain - evmDestChainStatePDA, _ := solState.FindDestChainStatePDA(evmChain, state.SolChains[solChain].Router) + evmDestChainStatePDA := state.SolChains[solChain].DestChainStatePDAs[evmChain] err = tenv.Env.SolChains[solChain].GetAccountDataBorshInto(ctx, evmDestChainStatePDA, &destChainStateAccount) require.NoError(t, err) } diff --git a/deployment/ccip/changeset/solana_state.go b/deployment/ccip/changeset/solana_state.go index 306115d78f2..1a4e8161a88 100644 --- a/deployment/ccip/changeset/solana_state.go +++ b/deployment/ccip/changeset/solana_state.go @@ -3,9 +3,12 @@ package changeset import ( "errors" "fmt" + "strconv" "github.com/gagliardetto/solana-go" + solState "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/state" + "github.com/smartcontractkit/chainlink/deployment" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" ) @@ -16,6 +19,9 @@ var ( Receiver deployment.ContractType = "Receiver" SPL2022Tokens deployment.ContractType = "SPL2022Tokens" WSOL deployment.ContractType = "WSOL" + // for PDAs from AddRemoteChainToSolana + RemoteSource deployment.ContractType = "RemoteSource" + RemoteDest deployment.ContractType = "RemoteDest" ) // SolChainState holds a Go binding for all the currently deployed CCIP programs @@ -29,6 +35,11 @@ type SolCCIPChainState struct { SPL2022Tokens []solana.PublicKey TokenPool solana.PublicKey WSOL solana.PublicKey + // PDAs to avoid redundant lookups + RouterStatePDA solana.PublicKey + RouterConfigPDA solana.PublicKey + SourceChainStatePDAs map[uint64]solana.PublicKey + DestChainStatePDAs map[uint64]solana.PublicKey } func LoadOnchainStateSolana(e deployment.Environment) (CCIPOnChainState, error) { @@ -55,28 +66,61 @@ func LoadOnchainStateSolana(e deployment.Environment) (CCIPOnChainState, error) // LoadChainStateSolana Loads all state for a SolChain into state func LoadChainStateSolana(chain deployment.SolChain, addresses map[string]deployment.TypeAndVersion) (SolCCIPChainState, error) { - var state SolCCIPChainState + state := SolCCIPChainState{ + SourceChainStatePDAs: make(map[uint64]solana.PublicKey), + DestChainStatePDAs: make(map[uint64]solana.PublicKey), + } var spl2022Tokens []solana.PublicKey for address, tvStr := range addresses { - switch tvStr.String() { - case deployment.NewTypeAndVersion(commontypes.LinkToken, deployment.Version1_0_0).String(): + switch tvStr.Type { + case commontypes.LinkToken: pub := solana.MustPublicKeyFromBase58(address) state.LinkToken = pub - case deployment.NewTypeAndVersion(Router, deployment.Version1_0_0).String(): + case Router: pub := solana.MustPublicKeyFromBase58(address) state.Router = pub - case deployment.NewTypeAndVersion(AddressLookupTable, deployment.Version1_0_0).String(): + routerStatePDA, _, err := solState.FindStatePDA(state.Router) + if err != nil { + return state, err + } + state.RouterStatePDA = routerStatePDA + routerConfigPDA, _, err := solState.FindConfigPDA(state.Router) + if err != nil { + return state, err + } + state.RouterConfigPDA = routerConfigPDA + case AddressLookupTable: pub := solana.MustPublicKeyFromBase58(address) state.AddressLookupTable = pub - case deployment.NewTypeAndVersion(Receiver, deployment.Version1_0_0).String(): + case Receiver: pub := solana.MustPublicKeyFromBase58(address) state.Receiver = pub - case deployment.NewTypeAndVersion(SPL2022Tokens, deployment.Version1_0_0).String(): + case SPL2022Tokens: pub := solana.MustPublicKeyFromBase58(address) spl2022Tokens = append(spl2022Tokens, pub) - case deployment.NewTypeAndVersion(TokenPool, deployment.Version1_0_0).String(): + case TokenPool: pub := solana.MustPublicKeyFromBase58(address) state.TokenPool = pub + case RemoteSource: + pub := solana.MustPublicKeyFromBase58(address) + // Labels should only have one entry + for selStr := range tvStr.Labels { + selector, err := strconv.ParseUint(selStr, 10, 64) + if err != nil { + return state, err + } + state.SourceChainStatePDAs[selector] = pub + } + case RemoteDest: + pub := solana.MustPublicKeyFromBase58(address) + // Labels should only have one entry + for selStr := range tvStr.Labels { + selector, err := strconv.ParseUint(selStr, 10, 64) + if err != nil { + return state, err + } + state.DestChainStatePDAs[selector] = pub + } default: return state, fmt.Errorf("unknown contract %s", tvStr) } diff --git a/deployment/ccip/changeset/testhelpers/test_helpers.go b/deployment/ccip/changeset/testhelpers/test_helpers.go index f394940b802..b2a5dc26653 100644 --- a/deployment/ccip/changeset/testhelpers/test_helpers.go +++ b/deployment/ccip/changeset/testhelpers/test_helpers.go @@ -1383,14 +1383,15 @@ func ValidateSolanaState(t *testing.T, e deployment.Environment, solChainSelecto // Validate addresses require.False(t, chainState.LinkToken.IsZero(), "Link token address is zero for chain %d", sel) require.False(t, chainState.Router.IsZero(), "Router address is zero for chain %d", sel) + require.False(t, chainState.RouterConfigPDA.IsZero(), "RouterConfigPDA is zero for chain %d", sel) + require.False(t, chainState.RouterStatePDA.IsZero(), "RouterStatePDA is zero for chain %d", sel) require.False(t, chainState.AddressLookupTable.IsZero(), "Address lookup table is zero for chain %d", sel) // Get router config var routerConfigAccount solRouter.Config - configPDA, _, _ := solState.FindConfigPDA(chainState.Router) // Check if account exists first - err = e.SolChains[sel].GetAccountDataBorshInto(testcontext.Get(t), configPDA, &routerConfigAccount) + err = e.SolChains[sel].GetAccountDataBorshInto(testcontext.Get(t), chainState.RouterConfigPDA, &routerConfigAccount) require.NoError(t, err, "Failed to deserialize router config for chain %d", sel) } } From 94d59c1453ed9b02c6e63758561d9bc813569e56 Mon Sep 17 00:00:00 2001 From: Christian Edward Jackson-Gruber Date: Fri, 31 Jan 2025 13:23:40 -0800 Subject: [PATCH 30/43] Extend ChangesetOutput to include a ProposedJobs slice, which contains the job spec, the node id, and the job id (as returned from the propose API of JD). Also, mark JobSpecs as deprecated. Once we remove all JobSpecs use, we can remove that field. (#16129) --- deployment/ccip/changeset/cs_deploy_chain.go | 1 + deployment/ccip/changeset/cs_home_chain.go | 1 + deployment/ccip/changeset/cs_jobspec.go | 2 ++ deployment/ccip/changeset/cs_jobspec_test.go | 1 + deployment/ccip/changeset/cs_prerequisites.go | 4 +++- deployment/changeset.go | 12 +++++++++++- deployment/common/changeset/save_existing.go | 1 + deployment/common/changeset/test_helpers.go | 4 ++++ 8 files changed, 24 insertions(+), 2 deletions(-) diff --git a/deployment/ccip/changeset/cs_deploy_chain.go b/deployment/ccip/changeset/cs_deploy_chain.go index 2042493ea1d..135b77398cb 100644 --- a/deployment/ccip/changeset/cs_deploy_chain.go +++ b/deployment/ccip/changeset/cs_deploy_chain.go @@ -59,6 +59,7 @@ func DeployChainContractsChangeset(env deployment.Environment, c DeployChainCont return deployment.ChangesetOutput{ Proposals: []timelock.MCMSWithTimelockProposal{}, AddressBook: newAddresses, + Jobs: nil, JobSpecs: nil, }, nil } diff --git a/deployment/ccip/changeset/cs_home_chain.go b/deployment/ccip/changeset/cs_home_chain.go index 9a691a8d8ab..90f4bcd7933 100644 --- a/deployment/ccip/changeset/cs_home_chain.go +++ b/deployment/ccip/changeset/cs_home_chain.go @@ -49,6 +49,7 @@ func DeployHomeChainChangeset(env deployment.Environment, cfg DeployHomeChainCon Proposals: []timelock.MCMSWithTimelockProposal{}, AddressBook: ab, JobSpecs: nil, + Jobs: nil, }, nil } diff --git a/deployment/ccip/changeset/cs_jobspec.go b/deployment/ccip/changeset/cs_jobspec.go index ffa331021c5..2ed6bd4aa15 100644 --- a/deployment/ccip/changeset/cs_jobspec.go +++ b/deployment/ccip/changeset/cs_jobspec.go @@ -6,6 +6,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" chainsel "github.com/smartcontractkit/chain-selectors" @@ -117,6 +118,7 @@ func CCIPCapabilityJobspecChangeset(env deployment.Environment, _ any) (deployme Proposals: []timelock.MCMSWithTimelockProposal{}, AddressBook: nil, JobSpecs: nodesToJobSpecs, + Jobs: nil, }, nil } diff --git a/deployment/ccip/changeset/cs_jobspec_test.go b/deployment/ccip/changeset/cs_jobspec_test.go index 11fececb244..8ffa810711d 100644 --- a/deployment/ccip/changeset/cs_jobspec_test.go +++ b/deployment/ccip/changeset/cs_jobspec_test.go @@ -21,6 +21,7 @@ func TestJobSpecChangeset(t *testing.T) { Chains: 1, Nodes: 4, }) + // TODO: Replace this with a changeset which proposes the jobs, and returns job ids. output, err := changeset.CCIPCapabilityJobspecChangeset(e, nil) require.NoError(t, err) require.NotNil(t, output.JobSpecs) diff --git a/deployment/ccip/changeset/cs_prerequisites.go b/deployment/ccip/changeset/cs_prerequisites.go index 94958d06f67..c5b1f12a6fa 100644 --- a/deployment/ccip/changeset/cs_prerequisites.go +++ b/deployment/ccip/changeset/cs_prerequisites.go @@ -7,9 +7,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "golang.org/x/sync/errgroup" + "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" @@ -53,6 +54,7 @@ func DeployPrerequisitesChangeset(env deployment.Environment, cfg DeployPrerequi Proposals: []timelock.MCMSWithTimelockProposal{}, AddressBook: ab, JobSpecs: nil, + Jobs: nil, }, nil } diff --git a/deployment/changeset.go b/deployment/changeset.go index abce4942203..fbde1dbb3d1 100644 --- a/deployment/changeset.go +++ b/deployment/changeset.go @@ -20,12 +20,22 @@ var ( // If the configuration is unexpected type or format, the changeset should return ErrInvalidConfig. type ChangeSet[C any] func(e Environment, config C) (ChangesetOutput, error) +// ProposedJob represents a job spec which has been proposed to a node, with the JobID returned by the +// Job Distributor. +type ProposedJob struct { + JobID string + Node string + Spec string +} + // ChangesetOutput is the output of a Changeset function. // Think of it like a state transition output. // The address book here should contain only new addresses created in // this changeset. type ChangesetOutput struct { - JobSpecs map[string][]string + // Deprecated: Prefer Jobs instead. + JobSpecs map[string][]string `deprecated:"true"` + Jobs []ProposedJob Proposals []timelock.MCMSWithTimelockProposal AddressBook AddressBook } diff --git a/deployment/common/changeset/save_existing.go b/deployment/common/changeset/save_existing.go index f06a90ba785..602d41dc84e 100644 --- a/deployment/common/changeset/save_existing.go +++ b/deployment/common/changeset/save_existing.go @@ -85,5 +85,6 @@ func SaveExistingContractsChangeset(env deployment.Environment, cfg ExistingCont Proposals: []timelock.MCMSWithTimelockProposal{}, AddressBook: ab, JobSpecs: nil, + Jobs: nil, }, nil } diff --git a/deployment/common/changeset/test_helpers.go b/deployment/common/changeset/test_helpers.go index a8105b26561..3c2409566eb 100644 --- a/deployment/common/changeset/test_helpers.go +++ b/deployment/common/changeset/test_helpers.go @@ -52,6 +52,7 @@ func ApplyChangesets(t *testing.T, e deployment.Environment, timelockContractsPe addresses = currentEnv.ExistingAddresses } if out.JobSpecs != nil { + // TODO: Delete this when out.JobSpecs are no longer in use. ctx := testcontext.Get(t) for nodeID, jobs := range out.JobSpecs { for _, job := range jobs { @@ -67,6 +68,9 @@ func ApplyChangesets(t *testing.T, e deployment.Environment, timelockContractsPe } } } + if out.Jobs != nil { + // do nothing, as these jobs auto-accept. + } if out.Proposals != nil { for _, prop := range out.Proposals { chains := mapset.NewSet[uint64]() From 91bc947595cd5ff280dab74110fc81111c125cb4 Mon Sep 17 00:00:00 2001 From: Anindita Ghosh <88458927+AnieeG@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:33:11 -0800 Subject: [PATCH 31/43] Fix static link issue in tooling (#16174) * remove deployCCIPContracts * deprecate existing add lane * add a test for static link * fix go import error * include solana chains * more fixes * more fix --- .../changeset/cs_active_candidate_test.go | 5 +- .../ccip/changeset/cs_ccip_home_test.go | 12 ++- deployment/ccip/changeset/cs_deploy_chain.go | 3 - .../ccip/changeset/cs_deploy_chain_test.go | 11 +++ .../changeset/testhelpers/test_environment.go | 97 +++++++++---------- deployment/ccip/changeset/token_info.go | 16 +-- .../common/changeset/deploy_link_token.go | 36 +++++++ 7 files changed, 115 insertions(+), 65 deletions(-) diff --git a/deployment/ccip/changeset/cs_active_candidate_test.go b/deployment/ccip/changeset/cs_active_candidate_test.go index 2d882ddddda..d0882a078c7 100644 --- a/deployment/ccip/changeset/cs_active_candidate_test.go +++ b/deployment/ccip/changeset/cs_active_candidate_test.go @@ -207,7 +207,10 @@ func Test_ActiveCandidate(t *testing.T) { // NOTE: this is technically not a new chain, but needed for validation. 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)), + changeset.WithDefaultCommitOffChainConfig(tenv.FeedChainSel, + tokenConfig.GetTokenInfo(logger.TestLogger(t), + state.Chains[dest].LinkToken.Address(), + state.Chains[dest].Weth9.Address())), ), }, PluginType: types.PluginTypeCCIPCommit, diff --git a/deployment/ccip/changeset/cs_ccip_home_test.go b/deployment/ccip/changeset/cs_ccip_home_test.go index 6020e96ff45..dcd6fe9f6b6 100644 --- a/deployment/ccip/changeset/cs_ccip_home_test.go +++ b/deployment/ccip/changeset/cs_ccip_home_test.go @@ -264,7 +264,11 @@ func Test_SetCandidate(t *testing.T) { { 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)), + changeset.WithDefaultCommitOffChainConfig( + tenv.FeedChainSel, + tokenConfig.GetTokenInfo(logger.TestLogger(t), + state.Chains[dest].LinkToken.Address(), + state.Chains[dest].Weth9.Address())), ), }, PluginType: types.PluginTypeCCIPCommit, @@ -377,7 +381,11 @@ func Test_RevokeCandidate(t *testing.T) { { 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)), + changeset.WithDefaultCommitOffChainConfig( + tenv.FeedChainSel, + tokenConfig.GetTokenInfo(logger.TestLogger(t), + state.Chains[dest].LinkToken.Address(), + state.Chains[dest].Weth9.Address())), ), }, PluginType: types.PluginTypeCCIPCommit, diff --git a/deployment/ccip/changeset/cs_deploy_chain.go b/deployment/ccip/changeset/cs_deploy_chain.go index 135b77398cb..b8305916947 100644 --- a/deployment/ccip/changeset/cs_deploy_chain.go +++ b/deployment/ccip/changeset/cs_deploy_chain.go @@ -248,9 +248,6 @@ func deployChainContractsForChains( return fmt.Errorf("fee tokens not valid for chain %d, staticLinkExists: %t, linkExists: %t, weth9Exists: %t", chainSel, staticLinkExists, linkExists, weth9Exists) } chain := e.Chains[chainSel] - if existingState.Chains[chainSel].LinkToken == nil || existingState.Chains[chainSel].Weth9 == nil { - return fmt.Errorf("fee tokens not found for chain %d", chainSel) - } deployFn = func() error { return deployChainContractsEVM(e, chain, ab, rmnHome, contractParams) } case chainsel.FamilySolana: diff --git a/deployment/ccip/changeset/cs_deploy_chain_test.go b/deployment/ccip/changeset/cs_deploy_chain_test.go index 79005de06be..027fa26ca92 100644 --- a/deployment/ccip/changeset/cs_deploy_chain_test.go +++ b/deployment/ccip/changeset/cs_deploy_chain_test.go @@ -109,3 +109,14 @@ func TestDeployCCIPContracts(t *testing.T) { t.Parallel() testhelpers.DeployCCIPContractsTest(t, 0) } + +func TestDeployStaticLinkToken(t *testing.T) { + t.Parallel() + e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithStaticLink()) + // load onchain state + state, err := changeset.LoadOnchainState(e.Env) + require.NoError(t, err) + for _, chain := range e.Env.AllChainSelectors() { + require.NotNil(t, state.Chains[chain].StaticLinkToken) + } +} diff --git a/deployment/ccip/changeset/testhelpers/test_environment.go b/deployment/ccip/changeset/testhelpers/test_environment.go index b2168084034..991d67a2e26 100644 --- a/deployment/ccip/changeset/testhelpers/test_environment.go +++ b/deployment/ccip/changeset/testhelpers/test_environment.go @@ -9,6 +9,7 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" @@ -22,6 +23,7 @@ import ( cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/globals" changeset_solana "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/solana" @@ -56,6 +58,7 @@ type TestConfigs struct { IsUSDC bool IsUSDCAttestationMissing bool IsMultiCall3 bool + IsStaticLink bool OCRConfigOverride func(*changeset.CCIPOCRParams) RMNEnabled bool NumOfRMNNodes int @@ -118,6 +121,12 @@ func WithMultiCall3() TestOps { } } +func WithStaticLink() TestOps { + return func(testCfg *TestConfigs) { + testCfg.IsStaticLink = true + } +} + func WithPrerequisiteDeploymentOnly(v1_5Cfg *changeset.V1_5DeploymentConfig) TestOps { return func(testCfg *TestConfigs) { testCfg.PrerequisiteDeploymentOnly = true @@ -400,14 +409,19 @@ func NewEnvironmentWithPrerequisitesContracts(t *testing.T, tEnv TestEnvironment var err error tc := tEnv.TestConfigs() e := NewEnvironment(t, tEnv) - allChains := e.Env.AllChainSelectors() - + evmChains := e.Env.AllChainSelectors() + solChains := e.Env.AllChainSelectorsSolana() + //nolint:gocritic // we need to segregate EVM and Solana chains + allChains := append(evmChains, solChains...) + if len(solChains) > 0 { + SavePreloadedSolAddresses(t, e.Env, solChains[0]) + } mcmsCfg := make(map[uint64]commontypes.MCMSWithTimelockConfig) for _, c := range e.Env.AllChainSelectors() { mcmsCfg[c] = proposalutils.SingleGroupTimelockConfig(t) } prereqCfg := make([]changeset.DeployPrerequisiteConfigPerChain, 0) - for _, chain := range allChains { + for _, chain := range evmChains { var opts []changeset.PrerequisiteOpt if tc != nil { if tc.IsUSDC { @@ -425,12 +439,18 @@ func NewEnvironmentWithPrerequisitesContracts(t *testing.T, tEnv TestEnvironment Opts: opts, }) } - - e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkToken), + deployLinkApp := commonchangeset.ChangesetApplication{ + Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkToken), + Config: allChains, + } + if tc.IsStaticLink { + deployLinkApp = commonchangeset.ChangesetApplication{ + Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployStaticLinkToken), Config: allChains, - }, + } + } + e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ + deployLinkApp, { Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisitesChangeset), Config: changeset.DeployPrerequisiteConfig{ @@ -465,56 +485,17 @@ func NewEnvironment(t *testing.T, tEnv TestEnvironment) DeployedEnv { func NewEnvironmentWithJobsAndContracts(t *testing.T, tEnv TestEnvironment) DeployedEnv { var err error - tc := tEnv.TestConfigs() - e := NewEnvironment(t, tEnv) + e := NewEnvironmentWithPrerequisitesContracts(t, tEnv) evmChains := e.Env.AllChainSelectors() solChains := e.Env.AllChainSelectorsSolana() //nolint:gocritic // we need to segregate EVM and Solana chains allChains := append(evmChains, solChains...) - if len(solChains) > 0 { - SavePreloadedSolAddresses(t, e.Env, solChains[0]) - } mcmsCfg := make(map[uint64]commontypes.MCMSWithTimelockConfig) for _, c := range e.Env.AllChainSelectors() { mcmsCfg[c] = proposalutils.SingleGroupTimelockConfig(t) } - prereqCfg := make([]changeset.DeployPrerequisiteConfigPerChain, 0) - for _, chain := range evmChains { - var opts []changeset.PrerequisiteOpt - if tc != nil { - if tc.IsUSDC { - opts = append(opts, changeset.WithUSDCEnabled()) - } - if tc.IsMultiCall3 { - opts = append(opts, changeset.WithMultiCall3Enabled()) - } - } - prereqCfg = append(prereqCfg, changeset.DeployPrerequisiteConfigPerChain{ - ChainSelector: chain, - Opts: opts, - }) - } - // Need to deploy prerequisites first so that we can form the USDC config - // 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(commonchangeset.DeployLinkToken), - Config: allChains, - }, - { - Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisitesChangeset), - Config: changeset.DeployPrerequisiteConfig{ - Configs: prereqCfg, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployMCMSWithTimelock), - Config: mcmsCfg, - }, - }) - require.NoError(t, err) tEnv.UpdateDeployedEnvironment(e) e = AddCCIPContractsToEnvironment(t, allChains, tEnv, false) @@ -590,7 +571,11 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) // Assert link present - require.NotNil(t, state.Chains[e.FeedChainSel].LinkToken) + if tc.IsStaticLink { + require.NotNil(t, state.Chains[e.FeedChainSel].StaticLinkToken) + } else { + require.NotNil(t, state.Chains[e.FeedChainSel].LinkToken) + } require.NotNil(t, state.Chains[e.FeedChainSel].Weth9) tokenConfig := changeset.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) @@ -633,7 +618,13 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn Timelock: state.Chains[chain].Timelock, CallProxy: state.Chains[chain].CallProxy, } - tokenInfo := tokenConfig.GetTokenInfo(e.Env.Logger, state.Chains[chain].LinkToken, state.Chains[chain].Weth9) + var linkTokenAddr common.Address + if tc.IsStaticLink { + linkTokenAddr = state.Chains[chain].StaticLinkToken.Address() + } else { + linkTokenAddr = state.Chains[chain].LinkToken.Address() + } + tokenInfo := tokenConfig.GetTokenInfo(e.Env.Logger, linkTokenAddr, state.Chains[chain].Weth9.Address()) ocrOverride := tc.OCRConfigOverride if tc.RMNEnabled { ocrOverride = func(ocrParams *changeset.CCIPOCRParams) { @@ -783,7 +774,11 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn require.NotNil(t, state.Chains[e.HomeChainSel].CCIPHome) require.NotNil(t, state.Chains[e.HomeChainSel].RMNHome) for _, chain := range evmChains { - require.NotNil(t, state.Chains[chain].LinkToken) + if tc.IsStaticLink { + require.NotNil(t, state.Chains[chain].StaticLinkToken) + } else { + require.NotNil(t, state.Chains[chain].LinkToken) + } require.NotNil(t, state.Chains[chain].Weth9) require.NotNil(t, state.Chains[chain].TokenAdminRegistry) require.NotNil(t, state.Chains[chain].RegistryModule) diff --git a/deployment/ccip/changeset/token_info.go b/deployment/ccip/changeset/token_info.go index bdd12764051..d11ebe2758a 100644 --- a/deployment/ccip/changeset/token_info.go +++ b/deployment/ccip/changeset/token_info.go @@ -3,16 +3,16 @@ package changeset import ( "math/big" + "github.com/ethereum/go-ethereum/common" + "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/deployment" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/aggregator_v3_interface" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" ) type TokenSymbol string @@ -105,15 +105,15 @@ func (tc *TokenConfig) UpsertTokenInfo( // GetTokenInfo Adds mapping between dest chain tokens and their respective aggregators on feed chain. func (tc *TokenConfig) GetTokenInfo( lggr logger.Logger, - linkToken *link_token.LinkToken, - wethToken *weth9.WETH9, + linkTokenAddr, + wethTokenAddr common.Address, ) map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo { tokenToAggregate := make(map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo) if _, ok := tc.TokenSymbolToInfo[LinkSymbol]; !ok { lggr.Debugw("Link aggregator not found, deploy without mapping link token") } else { lggr.Debugw("Mapping LinkToken to Link aggregator") - acc := ccipocr3.UnknownEncodedAddress(linkToken.Address().String()) + acc := ccipocr3.UnknownEncodedAddress(linkTokenAddr.String()) tokenToAggregate[acc] = tc.TokenSymbolToInfo[LinkSymbol] } @@ -121,7 +121,7 @@ func (tc *TokenConfig) GetTokenInfo( lggr.Debugw("Weth aggregator not found, deploy without mapping link token") } else { lggr.Debugw("Mapping WethToken to Weth aggregator") - acc := ccipocr3.UnknownEncodedAddress(wethToken.Address().String()) + acc := ccipocr3.UnknownEncodedAddress(wethTokenAddr.String()) tokenToAggregate[acc] = tc.TokenSymbolToInfo[WethSymbol] } diff --git a/deployment/common/changeset/deploy_link_token.go b/deployment/common/changeset/deploy_link_token.go index a87be060a8b..86783ea4118 100644 --- a/deployment/common/changeset/deploy_link_token.go +++ b/deployment/common/changeset/deploy_link_token.go @@ -2,6 +2,7 @@ package changeset import ( "context" + "fmt" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -13,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/link_token" ) @@ -56,6 +58,40 @@ func DeployLinkToken(e deployment.Environment, chains []uint64) (deployment.Chan return deployment.ChangesetOutput{AddressBook: newAddresses}, nil } +// DeployStaticLinkToken deploys a static link token contract to the chain identified by the ChainSelector. +func DeployStaticLinkToken(e deployment.Environment, chains []uint64) (deployment.ChangesetOutput, error) { + err := deployment.ValidateSelectorsInEnvironment(e, chains) + if err != nil { + return deployment.ChangesetOutput{}, err + } + newAddresses := deployment.NewMemoryAddressBook() + for _, chainSel := range chains { + chain, ok := e.Chains[chainSel] + if !ok { + return deployment.ChangesetOutput{}, fmt.Errorf("chain not found in environment: %d", chainSel) + } + _, err := deployment.DeployContract[*link_token_interface.LinkToken](e.Logger, chain, newAddresses, + func(chain deployment.Chain) deployment.ContractDeploy[*link_token_interface.LinkToken] { + linkTokenAddr, tx, linkToken, err2 := link_token_interface.DeployLinkToken( + chain.DeployerKey, + chain.Client, + ) + return deployment.ContractDeploy[*link_token_interface.LinkToken]{ + Address: linkTokenAddr, + Contract: linkToken, + Tx: tx, + Tv: deployment.NewTypeAndVersion(types.StaticLinkToken, deployment.Version1_0_0), + Err: err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy static link token", "chain", chain.String(), "err", err) + return deployment.ChangesetOutput{}, err + } + } + return deployment.ChangesetOutput{AddressBook: newAddresses}, nil +} + func deployLinkTokenContractEVM( lggr logger.Logger, chain deployment.Chain, From f791bf94118f2c7c7582722092870a6a8f26fbcb Mon Sep 17 00:00:00 2001 From: krehermann <16602512+krehermann@users.noreply.github.com> Date: Fri, 31 Jan 2025 16:20:58 -0700 Subject: [PATCH 32/43] make setup test deterministic (#16182) --- deployment/keystone/changeset/test/registry.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/deployment/keystone/changeset/test/registry.go b/deployment/keystone/changeset/test/registry.go index 88e2358a77e..9b1ce4ec8cc 100644 --- a/deployment/keystone/changeset/test/registry.go +++ b/deployment/keystone/changeset/test/registry.go @@ -3,6 +3,7 @@ package test import ( "context" "fmt" + "maps" "sort" "testing" "time" @@ -86,6 +87,7 @@ func SetupTestRegistry(t *testing.T, lggr logger.Logger, req *SetupTestRegistryR // ToNodeParams transforms a map of node operators to nops and a map of node p2pID to capabilities // must match the number of nodes. +// The order of returned nodeParams is deterministic and sorted by node operator name. func ToNodeParams(t *testing.T, nop2Nodes map[capabilities_registry.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc, p2pToCapabilities map[p2pkey.PeerID][][32]byte, @@ -94,7 +96,18 @@ func ToNodeParams(t *testing.T, var nodeParams []capabilities_registry.CapabilitiesRegistryNodeParams var i uint32 - for _, p2pSignerEncs := range nop2Nodes { + // deterministic order + // get the keys of the map and sort them + var keys []capabilities_registry.CapabilitiesRegistryNodeOperator + for k := range maps.Keys(nop2Nodes) { + keys = append(keys, k) + } + sort.Slice(keys, func(i, j int) bool { + return keys[i].Name < keys[j].Name + }) + for _, k := range keys { + p2pSignerEncs, ok := nop2Nodes[k] + require.True(t, ok, "missing node operator %s", k.Name) for _, p2pSignerEnc := range p2pSignerEncs { _, exists := p2pToCapabilities[p2pSignerEnc.P2PKey] require.True(t, exists, "missing capabilities for p2pID %s", p2pSignerEnc.P2PKey) @@ -104,7 +117,7 @@ func ToNodeParams(t *testing.T, P2pId: p2pSignerEnc.P2PKey, EncryptionPublicKey: p2pSignerEnc.EncryptionPublicKey, HashedCapabilityIds: p2pToCapabilities[p2pSignerEnc.P2PKey], - NodeOperatorId: i + 1, + NodeOperatorId: i + 1, // one-indexed }) } i++ From 2153289794891761e1941372988cf1c0baf624e0 Mon Sep 17 00:00:00 2001 From: Lukasz <120112546+lukaszcl@users.noreply.github.com> Date: Mon, 3 Feb 2025 07:58:13 +0100 Subject: [PATCH 33/43] TT-1974 Update flakeguard runner to prevent build failures for Solana artifacts (#16164) * Update flakeguard runner to prevent build failures for Solana artifacts * trigger test * Revert "trigger test" This reverts commit 81abb2d0c7f672d50ef5fabf4f2bc0ef9332664e. * Update the runner --- .github/workflows/flakeguard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flakeguard.yml b/.github/workflows/flakeguard.yml index 18947720579..499a0a94bf4 100644 --- a/.github/workflows/flakeguard.yml +++ b/.github/workflows/flakeguard.yml @@ -74,7 +74,7 @@ env: RUN_CUSTOM_TEST_PACKAGES: ${{ fromJSON(inputs.extraArgs)['run_custom_test_packages'] || '' }} # Comma-separated custom test packages to run. SHUFFLE_SEED: ${{ fromJSON(inputs.extraArgs)['shuffle_seed'] || '999' }} # The seed to use when -shuffle flag is enabled. Requires RUN_WITH_SHUFFLE to be true. ALL_TESTS_RUNNER: ${{ fromJSON(inputs.extraArgs)['all_tests_runner'] || 'ubuntu22.04-32cores-128GB' }} # The runner to use for running all tests. - DEFAULT_RUNNER: ${{ fromJSON(inputs.extraArgs)['default_tests_runner'] || 'ubuntu-latest' }} # The runner to use for running custom tests (e.g. in PRs). + DEFAULT_RUNNER: ${{ fromJSON(inputs.extraArgs)['default_tests_runner'] || 'ubuntu-latest-8cores-32GB' }} # The runner to use for running custom tests (e.g. in PRs). UPLOAD_ALL_TEST_RESULTS: ${{ fromJSON(inputs.extraArgs)['upload_all_test_results'] || 'false' }} # Whether to upload all test results as artifacts. OMIT_TEST_OUTPUTS_ON_SUCCESS: ${{ fromJSON(inputs.extraArgs)['omit_test_outputs_on_success'] || 'true' }} From ce0d4c12df8dd9fdb81695545d34a0cdff96aad2 Mon Sep 17 00:00:00 2001 From: Gabriel Paradiso Date: Mon, 3 Feb 2025 12:19:02 +0100 Subject: [PATCH 34/43] fix: make sure the trigger is registered before unregistering it (#16171) --- core/services/workflows/engine.go | 7 +- core/services/workflows/engine_test.go | 103 ++++++++++++++++++++----- core/services/workflows/models.go | 3 + 3 files changed, 90 insertions(+), 23 deletions(-) diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go index 3fdf0059ca4..abf4e59579d 100644 --- a/core/services/workflows/engine.go +++ b/core/services/workflows/engine.go @@ -470,6 +470,9 @@ func (e *Engine) registerTrigger(ctx context.Context, t *triggerCapability, trig }} } + // mark the trigger as successfully registered + t.registered = true + e.wg.Add(1) go func() { defer e.wg.Done() @@ -1037,10 +1040,10 @@ func (e *Engine) deregisterTrigger(ctx context.Context, t *triggerCapability, tr Config: t.config.Load(), } - // if t.trigger == nil, then we haven't initialized the workflow + // if t.trigger == nil or !t.registered, then we haven't initialized the workflow // yet, and can safely consider the trigger deregistered with // no further action. - if t.trigger != nil { + if t.trigger != nil && t.registered { return t.trigger.UnregisterTrigger(ctx, deregRequest) } diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index b4055e28e3c..0cfc4ff88b3 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -270,13 +270,15 @@ func (m *mockCapability) UnregisterFromWorkflow(ctx context.Context, request cap type mockTriggerCapability struct { capabilities.CapabilityInfo - triggerEvent *capabilities.TriggerResponse - ch chan capabilities.TriggerResponse + triggerEvent *capabilities.TriggerResponse + ch chan capabilities.TriggerResponse + registerTriggerCallCounter map[string]int } var _ capabilities.TriggerCapability = (*mockTriggerCapability)(nil) func (m *mockTriggerCapability) RegisterTrigger(ctx context.Context, req capabilities.TriggerRegistrationRequest) (<-chan capabilities.TriggerResponse, error) { + m.registerTriggerCallCounter[req.TriggerID]++ if m.triggerEvent != nil { m.ch <- *m.triggerEvent } @@ -284,6 +286,9 @@ func (m *mockTriggerCapability) RegisterTrigger(ctx context.Context, req capabil } func (m *mockTriggerCapability) UnregisterTrigger(ctx context.Context, req capabilities.TriggerRegistrationRequest) error { + if m.registerTriggerCallCounter[req.TriggerID] == 0 { + return errors.New("failed to unregister a non-registered trigger") + } return nil } @@ -384,7 +389,8 @@ func mockTrigger(t *testing.T) (capabilities.TriggerCapability, capabilities.Tri capabilities.CapabilityTypeTrigger, "issues a trigger when a mercury report is received.", ), - ch: make(chan capabilities.TriggerResponse, 10), + ch: make(chan capabilities.TriggerResponse, 10), + registerTriggerCallCounter: make(map[string]int), } resp, err := values.NewMap(map[string]any{ "123": decimal.NewFromFloat(1.00), @@ -410,7 +416,8 @@ func mockNoopTrigger(t *testing.T) capabilities.TriggerCapability { capabilities.CapabilityTypeTrigger, "issues a trigger when a mercury report is received.", ), - ch: make(chan capabilities.TriggerResponse, 10), + ch: make(chan capabilities.TriggerResponse, 10), + registerTriggerCallCounter: make(map[string]int), } return mt } @@ -1542,7 +1549,8 @@ func basicTestTrigger(t *testing.T) *mockTriggerCapability { capabilities.CapabilityTypeTrigger, "basic test trigger", ), - ch: make(chan capabilities.TriggerResponse, 10), + ch: make(chan capabilities.TriggerResponse, 10), + registerTriggerCallCounter: make(map[string]int), } resp, err := values.NewMap(map[string]any{ @@ -1745,10 +1753,11 @@ targets: type mockFetcher struct { retval map[string]string + retErr error } func (m *mockFetcher) SecretsFor(ctx context.Context, workflowOwner, hexWorkflowName, decodedWorkflowName, workflowID string) (map[string]string, error) { - return m.retval, nil + return m.retval, m.retErr } func TestEngine_FetchesSecrets(t *testing.T) { @@ -1783,34 +1792,86 @@ func TestEngine_FetchesSecrets(t *testing.T) { ) require.NoError(t, reg.Add(ctx, action)) + t.Run("successfully fetches secrets", func(t *testing.T) { + eng, testHooks := newTestEngineWithYAMLSpec( + t, + reg, + secretsWorkflow, + func(c *Config) { + c.SecretsFetcher = &mockFetcher{ + retval: map[string]string{ + "fidelity": "aFidelitySecret", + }, + } + }, + ) + + servicetest.Run(t, eng) + + eid := getExecutionID(t, eng, testHooks) + + state, err := eng.executionStates.Get(ctx, eid) + require.NoError(t, err) + + assert.Equal(t, store.StatusCompleted, state.Status) + + expected := map[string]any{ + "fidelityToken": "aFidelitySecret", + } + expm, err := values.Wrap(expected) + require.NoError(t, err) + assert.Equal(t, gotConfig, expm) + }) +} + +func TestEngine_CloseHappensOnlyIfWorkflowHasBeenRegistered(t *testing.T) { + ctx := testutils.Context(t) + reg := coreCap.NewRegistry(logger.TestLogger(t)) + + trigger, _ := mockTrigger(t) + + require.NoError(t, reg.Add(ctx, trigger)) + + require.NoError(t, reg.Add(ctx, mockConsensus(""))) + + target := mockTarget("write_ethereum-testnet-sepolia@1.0.0") + require.NoError(t, reg.Add(ctx, target)) + + action := newMockCapability( + // Create a remote capability so we don't use the local transmission protocol. + capabilities.MustNewRemoteCapabilityInfo( + "custom-compute@1.0.0", + capabilities.CapabilityTypeAction, + "a custom compute action with custom config", + &capabilities.DON{ID: 1}, + ), + func(req capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { + return capabilities.CapabilityResponse{ + Value: req.Inputs, + }, nil + }, + ) + require.NoError(t, reg.Add(ctx, action)) + eng, testHooks := newTestEngineWithYAMLSpec( t, reg, secretsWorkflow, func(c *Config) { c.SecretsFetcher = &mockFetcher{ - retval: map[string]string{ - "fidelity": "aFidelitySecret", - }, + retval: map[string]string{}, + retErr: errors.New("failed to fetch secrets XXX"), } }, ) - servicetest.Run(t, eng) - - eid := getExecutionID(t, eng, testHooks) - - state, err := eng.executionStates.Get(ctx, eid) + err := eng.Start(ctx) require.NoError(t, err) - assert.Equal(t, store.StatusCompleted, state.Status) - - expected := map[string]any{ - "fidelityToken": "aFidelitySecret", - } - expm, err := values.Wrap(expected) + // simulate WorkflowUpdatedEvent that calls tryEngineCleanup + <-testHooks.initFailed + err = eng.Close() require.NoError(t, err) - assert.Equal(t, gotConfig, expm) } func TestMerge(t *testing.T) { diff --git a/core/services/workflows/models.go b/core/services/workflows/models.go index d8abb0e9073..e14ad257819 100644 --- a/core/services/workflows/models.go +++ b/core/services/workflows/models.go @@ -116,6 +116,9 @@ type triggerCapability struct { sdk.StepDefinition trigger capabilities.TriggerCapability + // flag to track registration of the trigger and avoid removal of non registered triggers + registered bool + config atomic.Pointer[values.Map] } From 0d051fe8f868dc606028a1616b90ee1d7f11fca4 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 3 Feb 2025 07:36:15 -0600 Subject: [PATCH 35/43] core/chains/evm: simpler evm config (#16187) --- core/chains/evm/log/helpers_internal_test.go | 22 - core/chains/evm/log/helpers_test.go | 400 +----------------- core/chains/evm/log/integration_test.go | 390 ++++++++++++++++- core/chains/evm/log/orm_test.go | 8 + core/chains/evm/log/pool_test.go | 7 +- core/chains/evm/txmgr/broadcaster_test.go | 73 ++-- core/chains/evm/txmgr/confirmer_test.go | 207 +++++---- core/chains/evm/txmgr/evm_tx_store_test.go | 47 +- core/chains/evm/txmgr/finalizer_test.go | 7 +- .../evm/txmgr/stuck_tx_detector_test.go | 3 +- core/chains/evm/txmgr/txmgr_test.go | 20 +- core/chains/legacyevm/chain.go | 25 +- core/chains/legacyevm/chain_test.go | 2 +- core/cmd/shell.go | 2 +- core/cmd/shell_local_test.go | 25 +- core/config/app_config.go | 1 - core/internal/cltest/cltest.go | 2 +- core/internal/cltest/mocks.go | 7 +- core/internal/features/features_test.go | 2 +- core/internal/testutils/evmtest/evmtest.go | 12 +- core/internal/testutils/evmtest/v2/evmtest.go | 3 +- core/services/blockhashstore/bhs_test.go | 5 +- core/services/blockhashstore/delegate_test.go | 4 +- core/services/chainlink/application.go | 2 +- core/services/chainlink/config_general.go | 14 +- .../services/chainlink/config_general_test.go | 2 +- .../chainlink/mocks/general_config.go | 45 -- .../chainlink/relayer_chain_interoperators.go | 2 +- .../relayer_chain_interoperators_test.go | 4 +- core/services/directrequest/delegate_test.go | 9 +- core/services/feeds/orm_test.go | 2 +- core/services/feeds/service_test.go | 2 +- core/services/functions/listener_test.go | 5 +- .../headreporter/prometheus_reporter_test.go | 6 +- core/services/job/helpers_test.go | 5 +- core/services/job/job_orm_test.go | 18 +- .../job/job_pipeline_orm_integration_test.go | 5 +- core/services/job/runner_integration_test.go | 4 +- core/services/job/spawner_test.go | 4 +- .../keeper/registry1_1_synchronizer_test.go | 3 +- .../keeper/registry1_2_synchronizer_test.go | 3 +- .../keeper/registry1_3_synchronizer_test.go | 3 +- .../registry_synchronizer_helper_test.go | 4 +- core/services/keeper/upkeep_executer_test.go | 2 +- core/services/ocr2/delegate_test.go | 2 +- .../ccip/testhelpers/integration/chainlink.go | 2 +- .../testhelpers_1_4_0/chainlink.go | 2 +- core/services/pipeline/runner_test.go | 8 +- core/services/pipeline/task.eth_call_test.go | 2 +- core/services/pipeline/task.eth_tx_test.go | 2 +- core/services/relay/evm/relayer_extender.go | 4 +- .../relay/evm/relayer_extender_test.go | 2 +- core/services/vrf/delegate_test.go | 2 +- core/services/vrf/v2/integration_v2_test.go | 2 +- core/services/vrf/v2/listener_v2_test.go | 6 +- core/web/eth_keys_controller_test.go | 16 +- deployment/environment/memory/node.go | 2 +- evm/config/chain_scoped.go | 12 +- evm/config/configtest/configtest.go | 5 +- evm/config/toml/config.go | 11 + evm/gas/fee_history_estimator_test.go | 2 +- evm/testutils/config.go | 4 +- 62 files changed, 697 insertions(+), 807 deletions(-) delete mode 100644 core/chains/evm/log/helpers_internal_test.go diff --git a/core/chains/evm/log/helpers_internal_test.go b/core/chains/evm/log/helpers_internal_test.go deleted file mode 100644 index 59a3c4aadbc..00000000000 --- a/core/chains/evm/log/helpers_internal_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package log - -import ( - "github.com/ethereum/go-ethereum/core/types" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - - evmclient "github.com/smartcontractkit/chainlink/v2/evm/client" - evmtypes "github.com/smartcontractkit/chainlink/v2/evm/types" -) - -// NewTestBroadcaster creates a broadcaster with Pause/Resume enabled. -func NewTestBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *mailbox.Monitor) *broadcaster { - b := NewBroadcaster(orm, ethClient, config, lggr, highestSavedHead, mailMon) - b.testPause, b.testResume = make(chan struct{}), make(chan struct{}) - return b -} - -func (b *broadcaster) ExportedAppendLogChannel(ch1, ch2 <-chan types.Log) chan types.Log { - return b.appendLogChannel(ch1, ch2) -} diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index d24bf51d85b..59a3c4aadbc 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -1,404 +1,22 @@ -package log_test +package log import ( - "context" - "fmt" - "math/big" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" - logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" - "github.com/smartcontractkit/chainlink/v2/core/config" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmclient "github.com/smartcontractkit/chainlink/v2/evm/client" - "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" - evmconfig "github.com/smartcontractkit/chainlink/v2/evm/config" - "github.com/smartcontractkit/chainlink/v2/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink/v2/evm/types" ) -type broadcasterHelper struct { - t *testing.T - lb log.BroadcasterInTest - db *sqlx.DB - mockEth *clienttest.MockEth - globalConfig config.AppConfig - config evmconfig.EVM - - // each received channel corresponds to one eth subscription - chchRawLogs chan testutils.RawSub[types.Log] - toUnsubscribe []func() - pipelineHelper cltest.JobPipelineV2TestHelper -} - -func newBroadcasterHelper(t *testing.T, blockHeight int64, timesSubscribe int, filterLogsResult []types.Log, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { - // ensure we check before registering any mock Cleanup assertions - testutils.SkipShortDB(t) - - expectedCalls := mockEthClientExpectedCalls{ - SubscribeFilterLogs: timesSubscribe, - HeaderByNumber: 1, - FilterLogs: 1, - FilterLogsResult: filterLogsResult, - } - - chchRawLogs := make(chan testutils.RawSub[types.Log], timesSubscribe) - mockEth := newMockEthClient(t, chchRawLogs, blockHeight, expectedCalls) - helper := newBroadcasterHelperWithEthClient(t, mockEth.EthClient, nil, overridesFn) - helper.chchRawLogs = chchRawLogs - helper.mockEth = mockEth - return helper -} - -func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, highestSeenHead *evmtypes.Head, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { - globalConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.LogQueries = ptr(true) - finality := uint32(10) - c.EVM[0].FinalityDepth = &finality - - if overridesFn != nil { - overridesFn(c, s) - } - }) //TODO make evm directly - config := evmtest.NewChainScopedConfig(t, globalConfig).EVM() - lggr := logger.Test(t) - mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - - db := testutils.NewSqlxDB(t) - orm := log.NewORM(db, cltest.FixtureChainID) - lb := log.NewTestBroadcaster(orm, ethClient, config, lggr, highestSeenHead, mailMon) - kst := cltest.NewKeyStore(t, db) - - chainsAndConfig := evmtest.NewLegacyChainsAndConfig(t, evmtest.TestChainOpts{ - Client: ethClient, - GeneralConfig: globalConfig, - DatabaseConfig: globalConfig.Database(), - FeatureConfig: globalConfig.Feature(), - ListenerConfig: globalConfig.Database().Listener(), - DB: db, - KeyStore: kst.Eth(), - LogBroadcaster: &log.NullBroadcaster{}, - MailMon: mailMon, - }) - - m := make(map[string]legacyevm.Chain) - for _, r := range chainsAndConfig.Slice() { - m[r.ID().String()] = r - } - - legacyChains := chainsAndConfig.NewLegacyChains() - pipelineHelper := cltest.NewJobPipelineV2(t, globalConfig.WebServer(), globalConfig.JobPipeline(), legacyChains, db, kst, nil, nil) - - return &broadcasterHelper{ - t: t, - lb: lb, - db: db, - globalConfig: globalConfig, - config: config, - pipelineHelper: pipelineHelper, - toUnsubscribe: make([]func(), 0), - } -} - -func (helper *broadcasterHelper) start() { - err := helper.lb.Start(testutils.Context(helper.t)) - require.NoError(helper.t, err) -} - -func (helper *broadcasterHelper) register(listener log.Listener, contract log.AbigenContract, numConfirmations uint32) { - logs := []generated.AbigenLog{ - flux_aggregator_wrapper.FluxAggregatorNewRound{}, - flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}, - } - helper.registerWithTopics(listener, contract, logs, numConfirmations) -} - -func (helper *broadcasterHelper) registerWithTopics(listener log.Listener, contract log.AbigenContract, logs []generated.AbigenLog, numConfirmations uint32) { - logsWithTopics := make(map[common.Hash][][]log.Topic) - for _, log := range logs { - logsWithTopics[log.Topic()] = nil - } - helper.registerWithTopicValues(listener, contract, numConfirmations, logsWithTopics) -} - -func (helper *broadcasterHelper) registerWithTopicValues(listener log.Listener, contract log.AbigenContract, numConfirmations uint32, - topics map[common.Hash][][]log.Topic) { - unsubscribe := helper.lb.Register(listener, log.ListenerOpts{ - Contract: contract.Address(), - ParseLog: contract.ParseLog, - LogsWithTopics: topics, - MinIncomingConfirmations: numConfirmations, - }) - - helper.toUnsubscribe = append(helper.toUnsubscribe, unsubscribe) -} - -func (helper *broadcasterHelper) requireBroadcastCount(expectedCount int) { - helper.t.Helper() - g := gomega.NewGomegaWithT(helper.t) - - comparisonFunc := func() (int, error) { - var count struct{ Count int } - err := helper.db.Get(&count, `SELECT count(*) FROM log_broadcasts`) - return count.Count, err - } - - g.Eventually(comparisonFunc, testutils.WaitTimeout(helper.t), time.Second).Should(gomega.Equal(expectedCount)) - g.Consistently(comparisonFunc, 1*time.Second, 200*time.Millisecond).Should(gomega.Equal(expectedCount)) -} - -func (helper *broadcasterHelper) unsubscribeAll() { - for _, unsubscribe := range helper.toUnsubscribe { - unsubscribe() - } - time.Sleep(100 * time.Millisecond) -} -func (helper *broadcasterHelper) stop() { - err := helper.lb.Close() - assert.NoError(helper.t, err) -} - -func newMockContract(t *testing.T) *logmocks.AbigenContract { - addr := testutils.NewAddress() - contract := logmocks.NewAbigenContract(t) - contract.On("Address").Return(addr).Maybe() - return contract -} - -type logOnBlock struct { - logBlockNumber uint64 - blockNumber uint64 - blockHash common.Hash -} - -func (l logOnBlock) String() string { - return fmt.Sprintf("blockInfo(log:%v received on: %v %s)", l.logBlockNumber, l.blockNumber, l.blockHash) -} - -type received struct { - uniqueLogs []types.Log - logs []types.Log - broadcasts []log.Broadcast - sync.Mutex -} - -func newReceived(logs []types.Log) *received { - var rec received - rec.logs = logs - rec.uniqueLogs = logs - return &rec -} - -func (rec *received) getLogs() []types.Log { - rec.Lock() - defer rec.Unlock() - r := make([]types.Log, len(rec.logs)) - copy(r, rec.logs) - return r +// NewTestBroadcaster creates a broadcaster with Pause/Resume enabled. +func NewTestBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *mailbox.Monitor) *broadcaster { + b := NewBroadcaster(orm, ethClient, config, lggr, highestSavedHead, mailMon) + b.testPause, b.testResume = make(chan struct{}), make(chan struct{}) + return b } -func (rec *received) getUniqueLogs() []types.Log { - rec.Lock() - defer rec.Unlock() - r := make([]types.Log, len(rec.uniqueLogs)) - copy(r, rec.uniqueLogs) - return r -} - -func (rec *received) logsOnBlocks() []logOnBlock { - rec.Lock() - defer rec.Unlock() - var blocks []logOnBlock - for _, broadcast := range rec.broadcasts { - blocks = append(blocks, logOnBlock{ - logBlockNumber: broadcast.RawLog().BlockNumber, - blockNumber: broadcast.LatestBlockNumber(), - blockHash: broadcast.LatestBlockHash(), - }) - } - return blocks -} - -type simpleLogListener struct { - name string - lggr logger.SugaredLogger - received *received - t *testing.T - db *sqlx.DB - jobID int32 - skipMarkingConsumed atomic.Bool -} - -func (helper *broadcasterHelper) newLogListenerWithJob(name string) *simpleLogListener { - t := helper.t - db := helper.db - jb := &job.Job{ - Type: job.Cron, - SchemaVersion: 1, - CronSpec: &job.CronSpec{CronSchedule: "@every 1s"}, - PipelineSpec: &pipeline.Spec{}, - ExternalJobID: uuid.New(), - } - err := helper.pipelineHelper.Jrm.CreateJob(testutils.Context(t), jb) - require.NoError(t, err) - - var rec received - return &simpleLogListener{ - db: db, - lggr: logger.Sugared(logger.Test(t)), - name: name, - received: &rec, - t: t, - jobID: jb.ID, - } -} - -func (listener *simpleLogListener) SkipMarkingConsumed(skip bool) { - listener.skipMarkingConsumed.Store(skip) -} - -func (listener *simpleLogListener) HandleLog(ctx context.Context, lb log.Broadcast) { - listener.received.Lock() - defer listener.received.Unlock() - listener.lggr.Tracef("Listener %v HandleLog for block %v %v received at %v %v", listener.name, lb.RawLog().BlockNumber, lb.RawLog().BlockHash, lb.LatestBlockNumber(), lb.LatestBlockHash()) - - listener.received.logs = append(listener.received.logs, lb.RawLog()) - listener.received.broadcasts = append(listener.received.broadcasts, lb) - consumed := listener.handleLogBroadcast(ctx, lb) - - if !consumed { - listener.received.uniqueLogs = append(listener.received.uniqueLogs, lb.RawLog()) - } else { - listener.lggr.Warnf("Listener %v: Log was already consumed!", listener.name) - } -} - -func (listener *simpleLogListener) JobID() int32 { - return listener.jobID -} - -func (listener *simpleLogListener) getUniqueLogs() []types.Log { - return listener.received.getUniqueLogs() -} - -func (listener *simpleLogListener) getUniqueLogsBlockNumbers() []uint64 { - var blockNums []uint64 - for _, uniqueLog := range listener.received.getUniqueLogs() { - blockNums = append(blockNums, uniqueLog.BlockNumber) - } - return blockNums -} - -func (listener *simpleLogListener) requireAllReceived(t *testing.T, expectedState *received) { - received := listener.received - defer func() { assert.EqualValues(t, expectedState.getUniqueLogs(), received.getUniqueLogs()) }() - require.Eventually(t, func() bool { - return len(received.getUniqueLogs()) == len(expectedState.getUniqueLogs()) - }, testutils.WaitTimeout(t), time.Second, "len(received.uniqueLogs): %v is not equal len(expectedState.uniqueLogs): %v", len(received.getUniqueLogs()), len(expectedState.getUniqueLogs())) -} - -func (listener *simpleLogListener) handleLogBroadcast(ctx context.Context, lb log.Broadcast) bool { - t := listener.t - consumed, err := listener.WasAlreadyConsumed(ctx, lb) - if !assert.NoError(t, err) { - return false - } - if !consumed && !listener.skipMarkingConsumed.Load() { - err = listener.MarkConsumed(ctx, lb) - if assert.NoError(t, err) { - consumed2, err := listener.WasAlreadyConsumed(ctx, lb) - if assert.NoError(t, err) { - assert.True(t, consumed2) - } - } - } - return consumed -} - -func (listener *simpleLogListener) WasAlreadyConsumed(ctx context.Context, broadcast log.Broadcast) (bool, error) { - return log.NewORM(listener.db, cltest.FixtureChainID).WasBroadcastConsumed(ctx, broadcast.RawLog().BlockHash, broadcast.RawLog().Index, listener.jobID) -} - -func (listener *simpleLogListener) MarkConsumed(ctx context.Context, broadcast log.Broadcast) error { - return log.NewORM(listener.db, cltest.FixtureChainID).MarkBroadcastConsumed(ctx, broadcast.RawLog().BlockHash, broadcast.RawLog().BlockNumber, broadcast.RawLog().Index, listener.jobID) -} - -type mockListener struct { - jobID int32 -} - -func (l *mockListener) JobID() int32 { return l.jobID } -func (l *mockListener) HandleLog(context.Context, log.Broadcast) {} - -type mockEthClientExpectedCalls struct { - SubscribeFilterLogs int - HeaderByNumber int - FilterLogs int - - FilterLogsResult []types.Log -} - -func newMockEthClient(t *testing.T, chchRawLogs chan<- testutils.RawSub[types.Log], blockHeight int64, expectedCalls mockEthClientExpectedCalls) *clienttest.MockEth { - ethClient := clienttest.NewClient(t) - mockEth := &clienttest.MockEth{EthClient: ethClient} - mockEth.EthClient.On("ConfiguredChainID", mock.Anything).Return(&cltest.FixtureChainID) - mockEth.EthClient.On("SubscribeFilterLogs", mock.Anything, mock.Anything, mock.Anything). - Return( - func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) ethereum.Subscription { - sub := mockEth.NewSub(t) - chchRawLogs <- testutils.NewRawSub(ch, sub.Err()) - return sub - }, - func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) error { - return nil - }, - ). - Times(expectedCalls.SubscribeFilterLogs) - - mockEth.EthClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)). - Return(&evmtypes.Head{Number: blockHeight}, nil). - Times(expectedCalls.HeaderByNumber) - - if expectedCalls.FilterLogs > 0 { - mockEth.EthClient.On("FilterLogs", mock.Anything, mock.Anything). - Run(func(args mock.Arguments) { - filterQuery := args.Get(1).(ethereum.FilterQuery) - fromBlock := filterQuery.FromBlock.Int64() - toBlock := filterQuery.ToBlock.Int64() - if mockEth.CheckFilterLogs != nil { - mockEth.CheckFilterLogs(fromBlock, toBlock) - } - }). - Return(expectedCalls.FilterLogsResult, nil). - Times(expectedCalls.FilterLogs) - } - - return mockEth +func (b *broadcaster) ExportedAppendLogChannel(ch1, ch2 <-chan types.Log) chan types.Log { + return b.appendLogChannel(ch1, ch2) } diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index 58606437480..4cd5024b581 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -2,8 +2,10 @@ package log_test import ( "context" + "fmt" "math/big" "slices" + "sync" "sync/atomic" "testing" "time" @@ -11,6 +13,8 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/google/uuid" + "github.com/jmoiron/sqlx" "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -22,14 +26,20 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + evmclient "github.com/smartcontractkit/chainlink/v2/evm/client" "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" - evmtestutils "github.com/smartcontractkit/chainlink/v2/evm/testutils" + evmconfig "github.com/smartcontractkit/chainlink/v2/evm/config" + "github.com/smartcontractkit/chainlink/v2/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink/v2/evm/types" "github.com/smartcontractkit/chainlink/v2/evm/utils" ) @@ -82,7 +92,7 @@ func TestBroadcaster_ResubscribesOnAddOrRemoveContract(t *testing.T) { FilterLogs: backfillTimes, } - chchRawLogs := make(chan evmtestutils.RawSub[types.Log], backfillTimes) + chchRawLogs := make(chan testutils.RawSub[types.Log], backfillTimes) mockEth := newMockEthClient(t, chchRawLogs, blockHeight, expectedCalls) helper := newBroadcasterHelperWithEthClient(t, mockEth.EthClient, cltest.Head(lastStoredBlockHeight), nil) helper.mockEth = mockEth @@ -148,7 +158,7 @@ func TestBroadcaster_BackfillOnNodeStartAndOnReplay(t *testing.T) { FilterLogs: 2, } - chchRawLogs := make(chan evmtestutils.RawSub[types.Log], backfillTimes) + chchRawLogs := make(chan testutils.RawSub[types.Log], backfillTimes) mockEth := newMockEthClient(t, chchRawLogs, blockHeight, expectedCalls) helper := newBroadcasterHelperWithEthClient(t, mockEth.EthClient, cltest.Head(lastStoredBlockHeight), nil) helper.mockEth = mockEth @@ -205,7 +215,7 @@ func TestBroadcaster_ReplaysLogs(t *testing.T) { blocks.LogOnBlockNum(7, contract.Address()), } - mockEth := newMockEthClient(t, make(chan evmtestutils.RawSub[types.Log], 4), blockHeight, mockEthClientExpectedCalls{ + mockEth := newMockEthClient(t, make(chan testutils.RawSub[types.Log], 4), blockHeight, mockEthClientExpectedCalls{ FilterLogs: 4, FilterLogsResult: sentLogs, }) @@ -410,7 +420,7 @@ func TestBroadcaster_ShallowBackfillOnNodeStart(t *testing.T) { FilterLogs: backfillTimes, } - chchRawLogs := make(chan evmtestutils.RawSub[types.Log], backfillTimes) + chchRawLogs := make(chan testutils.RawSub[types.Log], backfillTimes) mockEth := newMockEthClient(t, chchRawLogs, blockHeight, expectedCalls) helper := newBroadcasterHelperWithEthClient(t, mockEth.EthClient, cltest.Head(lastStoredBlockHeight), func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].BlockBackfillSkip = ptr(true) @@ -460,7 +470,7 @@ func TestBroadcaster_BackfillInBatches(t *testing.T) { FilterLogs: expectedBatches, } - chchRawLogs := make(chan evmtestutils.RawSub[types.Log], backfillTimes) + chchRawLogs := make(chan testutils.RawSub[types.Log], backfillTimes) mockEth := newMockEthClient(t, chchRawLogs, blockHeight, expectedCalls) helper := newBroadcasterHelperWithEthClient(t, mockEth.EthClient, cltest.Head(lastStoredBlockHeight), func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].LogBackfillBatchSize = ptr(uint32(batchSize)) @@ -533,7 +543,7 @@ func TestBroadcaster_BackfillALargeNumberOfLogs(t *testing.T) { FilterLogsResult: backfilledLogs, } - chchRawLogs := make(chan evmtestutils.RawSub[types.Log], backfillTimes) + chchRawLogs := make(chan testutils.RawSub[types.Log], backfillTimes) mockEth := newMockEthClient(t, chchRawLogs, blockHeight, expectedCalls) helper := newBroadcasterHelperWithEthClient(t, mockEth.EthClient, cltest.Head(lastStoredBlockHeight), func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].LogBackfillBatchSize = ptr(batchSize) @@ -1014,7 +1024,7 @@ func TestBroadcaster_Register_ResubscribesToMostRecentlySeenBlock(t *testing.T) contract2 = newMockContract(t) ) mockEth := &clienttest.MockEth{EthClient: ethClient} - chchRawLogs := make(chan evmtestutils.RawSub[types.Log], backfillTimes) + chchRawLogs := make(chan testutils.RawSub[types.Log], backfillTimes) chStarted := make(chan struct{}) ethClient.On("ConfiguredChainID", mock.Anything).Return(&cltest.FixtureChainID) ethClient.On("SubscribeFilterLogs", mock.Anything, mock.Anything, mock.Anything). @@ -1022,7 +1032,7 @@ func TestBroadcaster_Register_ResubscribesToMostRecentlySeenBlock(t *testing.T) func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) ethereum.Subscription { defer close(chStarted) sub := mockEth.NewSub(t) - chchRawLogs <- evmtestutils.NewRawSub(ch, sub.Err()) + chchRawLogs <- testutils.NewRawSub(ch, sub.Err()) return sub }, func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) error { @@ -1035,7 +1045,7 @@ func TestBroadcaster_Register_ResubscribesToMostRecentlySeenBlock(t *testing.T) Return( func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) ethereum.Subscription { sub := mockEth.NewSub(t) - chchRawLogs <- evmtestutils.NewRawSub(ch, sub.Err()) + chchRawLogs <- testutils.NewRawSub(ch, sub.Err()) return sub }, func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) error { @@ -1326,7 +1336,7 @@ func TestBroadcaster_AppendLogChannel(t *testing.T) { ch2 := make(chan types.Log) ch3 := make(chan types.Log) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) mailMon := servicetest.RunHealthy(t, mailboxtest.NewMonitor(t)) lb := log.NewBroadcaster(nil, ethClient, nil, logger.Test(t), nil, mailMon) chCombined := lb.ExportedAppendLogChannel(ch1, ch2) @@ -1533,12 +1543,12 @@ func TestBroadcaster_BroadcastsWithZeroConfirmations(t *testing.T) { ethClient := clienttest.NewClient(t) mockEth := &clienttest.MockEth{EthClient: ethClient} ethClient.On("ConfiguredChainID").Return(big.NewInt(0)).Maybe() - logsChCh := make(chan evmtestutils.RawSub[types.Log]) + logsChCh := make(chan testutils.RawSub[types.Log]) ethClient.On("SubscribeFilterLogs", mock.Anything, mock.Anything, mock.Anything). Return( func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) ethereum.Subscription { sub := mockEth.NewSub(t) - logsChCh <- evmtestutils.NewRawSub(ch, sub.Err()) + logsChCh <- testutils.NewRawSub(ch, sub.Err()) return sub }, func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) error { @@ -1633,3 +1643,355 @@ func TestBroadcaster_BroadcastsWithZeroConfirmations(t *testing.T) { } func ptr[T any](t T) *T { return &t } + +func newBroadcasterHelper(t *testing.T, blockHeight int64, timesSubscribe int, filterLogsResult []types.Log, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { + // ensure we check before registering any mock Cleanup assertions + testutils.SkipShortDB(t) + + expectedCalls := mockEthClientExpectedCalls{ + SubscribeFilterLogs: timesSubscribe, + HeaderByNumber: 1, + FilterLogs: 1, + FilterLogsResult: filterLogsResult, + } + + chchRawLogs := make(chan testutils.RawSub[types.Log], timesSubscribe) + mockEth := newMockEthClient(t, chchRawLogs, blockHeight, expectedCalls) + helper := newBroadcasterHelperWithEthClient(t, mockEth.EthClient, nil, overridesFn) + helper.chchRawLogs = chchRawLogs + helper.mockEth = mockEth + return helper +} + +func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, highestSeenHead *evmtypes.Head, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { + globalConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.Database.LogQueries = ptr(true) + finality := uint32(10) + c.EVM[0].FinalityDepth = &finality + + if overridesFn != nil { + overridesFn(c, s) + } + }) + config := evmtest.NewChainScopedConfig(t, globalConfig).EVM() + lggr := logger.Test(t) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) + + db := testutils.NewSqlxDB(t) + orm := log.NewORM(db, cltest.FixtureChainID) + lb := log.NewTestBroadcaster(orm, ethClient, config, lggr, highestSeenHead, mailMon) + kst := cltest.NewKeyStore(t, db) + + chainsAndConfig := evmtest.NewLegacyChainsAndConfig(t, evmtest.TestChainOpts{ + Client: ethClient, + ChainConfigs: globalConfig.EVMConfigs(), + DatabaseConfig: globalConfig.Database(), + FeatureConfig: globalConfig.Feature(), + ListenerConfig: globalConfig.Database().Listener(), + DB: db, + KeyStore: kst.Eth(), + LogBroadcaster: &log.NullBroadcaster{}, + MailMon: mailMon, + }) + + m := make(map[string]legacyevm.Chain) + for _, r := range chainsAndConfig.Slice() { + m[r.ID().String()] = r + } + + legacyChains := chainsAndConfig.NewLegacyChains() + pipelineHelper := cltest.NewJobPipelineV2(t, globalConfig.WebServer(), globalConfig.JobPipeline(), legacyChains, db, kst, nil, nil) + + return &broadcasterHelper{ + t: t, + lb: lb, + db: db, + globalConfig: globalConfig, + config: config, + pipelineHelper: pipelineHelper, + toUnsubscribe: make([]func(), 0), + } +} + +type broadcasterHelper struct { + t *testing.T + lb log.BroadcasterInTest + db *sqlx.DB + mockEth *clienttest.MockEth + globalConfig config.AppConfig + config evmconfig.EVM + + // each received channel corresponds to one eth subscription + chchRawLogs chan testutils.RawSub[types.Log] + toUnsubscribe []func() + pipelineHelper cltest.JobPipelineV2TestHelper +} + +func (helper *broadcasterHelper) start() { + err := helper.lb.Start(testutils.Context(helper.t)) + require.NoError(helper.t, err) +} + +func (helper *broadcasterHelper) register(listener log.Listener, contract log.AbigenContract, numConfirmations uint32) { + logs := []generated.AbigenLog{ + flux_aggregator_wrapper.FluxAggregatorNewRound{}, + flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}, + } + helper.registerWithTopics(listener, contract, logs, numConfirmations) +} + +func (helper *broadcasterHelper) registerWithTopics(listener log.Listener, contract log.AbigenContract, logs []generated.AbigenLog, numConfirmations uint32) { + logsWithTopics := make(map[common.Hash][][]log.Topic) + for _, log := range logs { + logsWithTopics[log.Topic()] = nil + } + helper.registerWithTopicValues(listener, contract, numConfirmations, logsWithTopics) +} + +func (helper *broadcasterHelper) registerWithTopicValues(listener log.Listener, contract log.AbigenContract, numConfirmations uint32, + topics map[common.Hash][][]log.Topic) { + unsubscribe := helper.lb.Register(listener, log.ListenerOpts{ + Contract: contract.Address(), + ParseLog: contract.ParseLog, + LogsWithTopics: topics, + MinIncomingConfirmations: numConfirmations, + }) + + helper.toUnsubscribe = append(helper.toUnsubscribe, unsubscribe) +} + +func (helper *broadcasterHelper) requireBroadcastCount(expectedCount int) { + helper.t.Helper() + g := gomega.NewGomegaWithT(helper.t) + + comparisonFunc := func() (int, error) { + var count struct{ Count int } + err := helper.db.Get(&count, `SELECT count(*) FROM log_broadcasts`) + return count.Count, err + } + + g.Eventually(comparisonFunc, testutils.WaitTimeout(helper.t), time.Second).Should(gomega.Equal(expectedCount)) + g.Consistently(comparisonFunc, 1*time.Second, 200*time.Millisecond).Should(gomega.Equal(expectedCount)) +} + +func (helper *broadcasterHelper) unsubscribeAll() { + for _, unsubscribe := range helper.toUnsubscribe { + unsubscribe() + } + time.Sleep(100 * time.Millisecond) +} +func (helper *broadcasterHelper) stop() { + err := helper.lb.Close() + assert.NoError(helper.t, err) +} + +func newMockContract(t *testing.T) *logmocks.AbigenContract { + addr := testutils.NewAddress() + contract := logmocks.NewAbigenContract(t) + contract.On("Address").Return(addr).Maybe() + return contract +} + +type logOnBlock struct { + logBlockNumber uint64 + blockNumber uint64 + blockHash common.Hash +} + +func (l logOnBlock) String() string { + return fmt.Sprintf("blockInfo(log:%v received on: %v %s)", l.logBlockNumber, l.blockNumber, l.blockHash) +} + +type received struct { + uniqueLogs []types.Log + logs []types.Log + broadcasts []log.Broadcast + sync.Mutex +} + +func newReceived(logs []types.Log) *received { + var rec received + rec.logs = logs + rec.uniqueLogs = logs + return &rec +} + +func (rec *received) getLogs() []types.Log { + rec.Lock() + defer rec.Unlock() + r := make([]types.Log, len(rec.logs)) + copy(r, rec.logs) + return r +} + +func (rec *received) getUniqueLogs() []types.Log { + rec.Lock() + defer rec.Unlock() + r := make([]types.Log, len(rec.uniqueLogs)) + copy(r, rec.uniqueLogs) + return r +} + +func (rec *received) logsOnBlocks() []logOnBlock { + rec.Lock() + defer rec.Unlock() + var blocks []logOnBlock + for _, broadcast := range rec.broadcasts { + blocks = append(blocks, logOnBlock{ + logBlockNumber: broadcast.RawLog().BlockNumber, + blockNumber: broadcast.LatestBlockNumber(), + blockHash: broadcast.LatestBlockHash(), + }) + } + return blocks +} + +type simpleLogListener struct { + name string + lggr logger.SugaredLogger + received *received + t *testing.T + db *sqlx.DB + jobID int32 + skipMarkingConsumed atomic.Bool +} + +func (helper *broadcasterHelper) newLogListenerWithJob(name string) *simpleLogListener { + t := helper.t + db := helper.db + jb := &job.Job{ + Type: job.Cron, + SchemaVersion: 1, + CronSpec: &job.CronSpec{CronSchedule: "@every 1s"}, + PipelineSpec: &pipeline.Spec{}, + ExternalJobID: uuid.New(), + } + err := helper.pipelineHelper.Jrm.CreateJob(testutils.Context(t), jb) + require.NoError(t, err) + + var rec received + return &simpleLogListener{ + db: db, + lggr: logger.Sugared(logger.Test(t)), + name: name, + received: &rec, + t: t, + jobID: jb.ID, + } +} + +func (listener *simpleLogListener) SkipMarkingConsumed(skip bool) { + listener.skipMarkingConsumed.Store(skip) +} + +func (listener *simpleLogListener) HandleLog(ctx context.Context, lb log.Broadcast) { + listener.received.Lock() + defer listener.received.Unlock() + listener.lggr.Tracef("Listener %v HandleLog for block %v %v received at %v %v", listener.name, lb.RawLog().BlockNumber, lb.RawLog().BlockHash, lb.LatestBlockNumber(), lb.LatestBlockHash()) + + listener.received.logs = append(listener.received.logs, lb.RawLog()) + listener.received.broadcasts = append(listener.received.broadcasts, lb) + consumed := listener.handleLogBroadcast(ctx, lb) + + if !consumed { + listener.received.uniqueLogs = append(listener.received.uniqueLogs, lb.RawLog()) + } else { + listener.lggr.Warnf("Listener %v: Log was already consumed!", listener.name) + } +} + +func (listener *simpleLogListener) JobID() int32 { + return listener.jobID +} + +func (listener *simpleLogListener) getUniqueLogs() []types.Log { + return listener.received.getUniqueLogs() +} + +func (listener *simpleLogListener) getUniqueLogsBlockNumbers() []uint64 { + var blockNums []uint64 + for _, uniqueLog := range listener.received.getUniqueLogs() { + blockNums = append(blockNums, uniqueLog.BlockNumber) + } + return blockNums +} + +func (listener *simpleLogListener) requireAllReceived(t *testing.T, expectedState *received) { + received := listener.received + defer func() { assert.EqualValues(t, expectedState.getUniqueLogs(), received.getUniqueLogs()) }() + require.Eventually(t, func() bool { + return len(received.getUniqueLogs()) == len(expectedState.getUniqueLogs()) + }, testutils.WaitTimeout(t), time.Second, "len(received.uniqueLogs): %v is not equal len(expectedState.uniqueLogs): %v", len(received.getUniqueLogs()), len(expectedState.getUniqueLogs())) +} + +func (listener *simpleLogListener) handleLogBroadcast(ctx context.Context, lb log.Broadcast) bool { + t := listener.t + consumed, err := listener.WasAlreadyConsumed(ctx, lb) + if !assert.NoError(t, err) { + return false + } + if !consumed && !listener.skipMarkingConsumed.Load() { + err = listener.MarkConsumed(ctx, lb) + if assert.NoError(t, err) { + consumed2, err := listener.WasAlreadyConsumed(ctx, lb) + if assert.NoError(t, err) { + assert.True(t, consumed2) + } + } + } + return consumed +} + +func (listener *simpleLogListener) WasAlreadyConsumed(ctx context.Context, broadcast log.Broadcast) (bool, error) { + return log.NewORM(listener.db, cltest.FixtureChainID).WasBroadcastConsumed(ctx, broadcast.RawLog().BlockHash, broadcast.RawLog().Index, listener.jobID) +} + +func (listener *simpleLogListener) MarkConsumed(ctx context.Context, broadcast log.Broadcast) error { + return log.NewORM(listener.db, cltest.FixtureChainID).MarkBroadcastConsumed(ctx, broadcast.RawLog().BlockHash, broadcast.RawLog().BlockNumber, broadcast.RawLog().Index, listener.jobID) +} + +type mockEthClientExpectedCalls struct { + SubscribeFilterLogs int + HeaderByNumber int + FilterLogs int + + FilterLogsResult []types.Log +} + +func newMockEthClient(t *testing.T, chchRawLogs chan<- testutils.RawSub[types.Log], blockHeight int64, expectedCalls mockEthClientExpectedCalls) *clienttest.MockEth { + ethClient := clienttest.NewClient(t) + mockEth := &clienttest.MockEth{EthClient: ethClient} + mockEth.EthClient.On("ConfiguredChainID", mock.Anything).Return(&cltest.FixtureChainID) + mockEth.EthClient.On("SubscribeFilterLogs", mock.Anything, mock.Anything, mock.Anything). + Return( + func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) ethereum.Subscription { + sub := mockEth.NewSub(t) + chchRawLogs <- testutils.NewRawSub(ch, sub.Err()) + return sub + }, + func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) error { + return nil + }, + ). + Times(expectedCalls.SubscribeFilterLogs) + + mockEth.EthClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)). + Return(&evmtypes.Head{Number: blockHeight}, nil). + Times(expectedCalls.HeaderByNumber) + + if expectedCalls.FilterLogs > 0 { + mockEth.EthClient.On("FilterLogs", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + filterQuery := args.Get(1).(ethereum.FilterQuery) + fromBlock := filterQuery.FromBlock.Int64() + toBlock := filterQuery.ToBlock.Int64() + if mockEth.CheckFilterLogs != nil { + mockEth.CheckFilterLogs(fromBlock, toBlock) + } + }). + Return(expectedCalls.FilterLogsResult, nil). + Times(expectedCalls.FilterLogs) + } + + return mockEth +} diff --git a/core/chains/evm/log/orm_test.go b/core/chains/evm/log/orm_test.go index c1c9c54d82c..be8cbaa4b5a 100644 --- a/core/chains/evm/log/orm_test.go +++ b/core/chains/evm/log/orm_test.go @@ -1,6 +1,7 @@ package log_test import ( + "context" "math/big" "math/rand" "testing" @@ -238,3 +239,10 @@ func TestORM_Reinitialize(t *testing.T) { }) } } + +type mockListener struct { + jobID int32 +} + +func (l *mockListener) JobID() int32 { return l.jobID } +func (l *mockListener) HandleLog(context.Context, log.Broadcast) {} diff --git a/core/chains/evm/log/pool_test.go b/core/chains/evm/log/pool_test.go index c4789f5acd4..50b16f51954 100644 --- a/core/chains/evm/log/pool_test.go +++ b/core/chains/evm/log/pool_test.go @@ -4,13 +4,12 @@ import ( "math/big" "testing" - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" ) var ( diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index ad7342c9707..9bdd9614cb5 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -65,7 +65,7 @@ func NewTestEthBroadcaster( ethClient client.Client, keyStore keystore.Eth, databaseListener txmgr.ListenerConfig, - config evmconfig.ChainScopedConfig, + config evmconfig.EVM, checkerFactory txmgr.TransmitCheckerFactory, nonceAutoSync bool, nonceTracker txmgr.NonceTracker, @@ -73,17 +73,17 @@ func NewTestEthBroadcaster( t.Helper() lggr := logger.Test(t) - ge := config.EVM().GasEstimator() + ge := config.GasEstimator() estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { - return gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), nil, ge.BlockHistory(), lggr, nil) + return gas.NewFixedPriceEstimator(config.GasEstimator(), nil, ge.BlockHistory(), lggr, nil) }, ge.EIP1559DynamicFees(), ge, ethClient) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) ethBroadcaster := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), - txmgr.NewEvmTxmConfig(config.EVM()), - txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), - config.EVM().Transactions(), + txmgr.NewEvmTxmConfig(config), + txmgr.NewEvmTxmFeeConfig(config.GasEstimator()), + config.Transactions(), databaseListener, keyStore, txBuilder, nonceTracker, lggr, checkerFactory, nonceAutoSync, "") @@ -199,7 +199,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { ethClient.On("NonceAt", mock.Anything, otherAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, checkerFactory, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), checkerFactory, false, nonceTracker) toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") timeNow := time.Now() @@ -398,7 +398,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }) ethClient.On("NonceAt", mock.Anything, otherAddress, mock.Anything).Return(uint64(1), nil).Once() nonceTracker = txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, checkerFactory, false, nonceTracker) + eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), checkerFactory, false, nonceTracker) t.Run("sends transactions with type 0x2 in EIP-1559 mode", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -566,7 +566,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { checkerFactory := &testCheckerFactory{} ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, checkerFactory, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), checkerFactory, false, nonceTracker) checker := txmgr.TransmitCheckerSpec{ CheckerType: txmgr.TransmitCheckerTypeSimulate, @@ -715,7 +715,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { assert.Equal(t, int(1600), int(tx.Gas())) @@ -748,7 +748,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { nextNonce := evmtypes.Nonce(916714082576372851) firstNonce := nextNonce secondNonce := nextNonce + 1 - evmcfg := configtest.NewChainScopedConfig(t, nil) ctx := tests.Context(t) t.Run("cannot be more than one transaction per address in an unfinished state", func(t *testing.T) { @@ -789,14 +788,14 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce but never broadcast", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - + evmcfg := configtest.NewChainScopedConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so evm.key_states.next_nonce has not been @@ -828,14 +827,14 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce and broadcast but it fatally errored before we could save", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - + evmcfg := configtest.NewChainScopedConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -865,14 +864,14 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce and broadcast and is now in mempool", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - + evmcfg := configtest.NewChainScopedConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -901,14 +900,14 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce and broadcast and now the transaction has been confirmed", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - + evmcfg := configtest.NewChainScopedConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -939,14 +938,14 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { failedToReachNodeError := context.DeadlineExceeded db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - + evmcfg := configtest.NewChainScopedConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -987,7 +986,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -1046,13 +1045,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) txmClient := txmgr.NewEvmTxmClient(ethClient, nil) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmClient) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, configtest.NewChainScopedConfig(t, nil).EVM(), &testCheckerFactory{}, false, nonceTracker) ctx := tests.Context(t) require.NoError(t, commonutils.JustError(db.Exec(`SET CONSTRAINTS fk_pipeline_runs_pruning_key DEFERRED`))) @@ -1181,6 +1179,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // same as the parent test, but callback is set by ctor t.Run("callback set by ctor", func(t *testing.T) { + evmcfg := configtest.NewChainScopedConfig(t, nil) estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), nil, evmcfg.EVM().GasEstimator().BlockHistory(), lggr, nil) }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator(), ethClient) @@ -1396,7 +1395,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { underpricedError := "transaction underpriced" localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID) - + evmcfg := configtest.NewChainScopedConfig(t, nil) // First was underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasPrice().Cmp(evmcfg.EVM().GasEstimator().PriceDefault().ToInt()) == 0 @@ -1506,16 +1505,16 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // In this scenario the node operator REALLY fucked up and set the bump // to zero (even though that should not be possible due to config // validation) - evmcfg2 := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.BumpMin = assets.NewWeiI(0) c.GasEstimator.BumpPercent = ptr[uint16](0) }) - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID) // First was underpriced ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == localNextNonce && tx.GasPrice().Cmp(evmcfg2.EVM().GasEstimator().PriceDefault().ToInt()) == 0 + return tx.Nonce() == localNextNonce && tx.GasPrice().Cmp(evmcfg.EVM().GasEstimator().PriceDefault().ToInt()) == 0 }), fromAddress).Return(multinode.Underpriced, errors.New(underpricedError)).Once() // Do the thing @@ -1595,14 +1594,14 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // In this scenario the node operator REALLY fucked up and set the bump // to zero (even though that should not be possible due to config // validation) - evmcfg2 := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.EIP1559DynamicFees = ptr(true) c.GasEstimator.BumpMin = assets.NewWeiI(0) c.GasEstimator.BumpPercent = ptr[uint16](0) }) localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID) underpricedError := "transaction underpriced" localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) @@ -1628,13 +1627,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { gasTipCapDefault := assets.NewWeiI(42) - evmcfg2 := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.EIP1559DynamicFees = ptr(true) c.GasEstimator.TipCapDefault = gasTipCapDefault }) localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) // Second was underpriced but above minimum ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1642,11 +1641,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(multinode.Underpriced, errors.New(underpricedError)).Once() // Resend at the bumped price ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(0).Add(gasTipCapDefault.ToInt(), evmcfg2.EVM().GasEstimator().BumpMin().ToInt())) == 0 + return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(0).Add(gasTipCapDefault.ToInt(), evmcfg.EVM().GasEstimator().BumpMin().ToInt())) == 0 }), fromAddress).Return(multinode.Underpriced, errors.New(underpricedError)).Once() // Final bump succeeds ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(0).Add(gasTipCapDefault.ToInt(), big.NewInt(0).Mul(evmcfg2.EVM().GasEstimator().BumpMin().ToInt(), big.NewInt(2)))) == 0 + return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(0).Add(gasTipCapDefault.ToInt(), big.NewInt(0).Mul(evmcfg.EVM().GasEstimator().BumpMin().ToInt(), big.NewInt(2)))) == 0 }), fromAddress).Return(multinode.Successful, nil).Once() retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) @@ -1747,7 +1746,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) ctx := tests.Context(t) _, err := nonceTracker.GetNextSequence(ctx, fromAddress) require.NoError(t, err) @@ -1795,7 +1794,7 @@ func TestEthBroadcaster_Trigger(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, &testCheckerFactory{}, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) eb.Trigger(testutils.NewAddress()) eb.Trigger(testutils.NewAddress()) @@ -1865,7 +1864,7 @@ func TestEthBroadcaster_NonceTracker_InProgressTx(t *testing.T) { // Tx with nonce 0 in DB will set local nonce map to value to 1 mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(inProgressTxNonce), fromAddress) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg, checkerFactory, false, nonceTracker) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), checkerFactory, false, nonceTracker) // Check the local nonce map was set to 1 higher than in-progress tx nonce nonce := getLocalNextNonce(t, nonceTracker, fromAddress) diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index fd1b5c154f9..c1b19992a09 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/v2/evm/config/toml" "github.com/smartcontractkit/chainlink-framework/chains/fees" txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" @@ -29,13 +30,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/evm/assets" "github.com/smartcontractkit/chainlink/v2/evm/client" "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" evmconfig "github.com/smartcontractkit/chainlink/v2/evm/config" + "github.com/smartcontractkit/chainlink/v2/evm/config/configtest" "github.com/smartcontractkit/chainlink/v2/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/evm/keystore" @@ -45,11 +44,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/evm/utils" ) -func newTestChainScopedConfig(t *testing.T) (chainlink.GeneralConfig, evmconfig.ChainScopedConfig) { - cfg := configtest.NewTestGeneralConfig(t) - return cfg, evmtest.NewChainScopedConfig(t, cfg) -} - func newBroadcastLegacyEthTxAttempt(t *testing.T, etxID int64, gasPrice ...int64) txmgr.TxAttempt { attempt := cltest.NewLegacyEthTxAttempt(t, etxID) attempt.State = txmgrtypes.TxAttemptBroadcast @@ -107,7 +101,7 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - gconfig, config := newTestChainScopedConfig(t) + config := configtest.NewChainScopedConfig(t, nil) txStore := newTxStore(t, db) ethClient := clienttest.NewClientWithDefaultChainID(t) @@ -124,7 +118,7 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), config.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient) ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), gconfig.Database(), ethKeyStore, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), confirmerConfig{}, ethKeyStore, txBuilder, lggr, stuckTxDetector, ht) ctx := tests.Context(t) // Can't close unstarted instance @@ -187,12 +181,11 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) - }) txStore := cltest.NewTestTxStore(t, db) ethClient := clienttest.NewClientWithDefaultChainID(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.PriceMax = assets.GWei(500) + }) ctx := tests.Context(t) blockNum := int64(100) @@ -207,7 +200,7 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx1 := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 0, blockNum) etx2 := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 4, fromAddress, 1, blockNum, assets.NewWeiI(1)) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(1), nil).Maybe() require.NoError(t, ec.CheckForConfirmation(ctx, &head)) @@ -227,7 +220,7 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // Insert confirmed transaction that stays confirmed etx := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 0, blockNum) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Maybe() require.NoError(t, ec.CheckForConfirmation(ctx, &head)) @@ -247,7 +240,7 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { // Insert terminally stuck transaction that stays fatal error etx := mustInsertTerminallyStuckTxWithAttempt(t, txStore, fromAddress, 0, blockNum) mustInsertEthReceipt(t, txStore, blockNum, utils.NewHash(), etx.TxAttempts[0].Hash) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Maybe() require.NoError(t, ec.CheckForConfirmation(ctx, &head)) @@ -277,7 +270,7 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { mustInsertEthReceipt(t, txStore, blockNum, utils.NewHash(), etx4.TxAttempts[0].Hash) // Insert unconfirmed transaction that is untouched etx5 := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 4, fromAddress, 1, blockNum, assets.NewWeiI(1)) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(2), nil).Maybe() require.NoError(t, ec.CheckForConfirmation(ctx, &head)) @@ -325,7 +318,7 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, blockNum, assets.NewWeiI(1)) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(1), nil).Maybe() require.NoError(t, ec.CheckForConfirmation(ctx, &head)) @@ -340,7 +333,7 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := mustInsertUnconfirmedEthTxWithBroadcastPurgeAttempt(t, txStore, 0, fromAddress) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(1), nil).Maybe() require.NoError(t, ec.CheckForConfirmation(ctx, &head)) @@ -366,7 +359,7 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { etx4 := mustInsertUnconfirmedEthTxWithBroadcastPurgeAttempt(t, txStore, 3, fromAddress) // Insert unconfirmed transact that is not confirmed and left untouched etx5 := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 4, fromAddress, 1, blockNum, assets.NewWeiI(1)) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(4), nil).Maybe() require.NoError(t, ec.CheckForConfirmation(ctx, &head)) @@ -416,13 +409,12 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db) ctx := tests.Context(t) ethClient := clienttest.NewClientWithDefaultChainID(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db).Eth() @@ -443,7 +435,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { lggr := logger.Test(t) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) t.Run("returns nothing when there are no transactions", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(tests.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -713,12 +705,11 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing ethClient := clienttest.NewClientWithDefaultChainID(t) t.Run("should retry previous attempt if connectivity check failed for legacy transactions", func(t *testing.T) { - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(false) - c.EVM[0].GasEstimator.BlockHistory.BlockHistorySize = ptr[uint16](2) - c.EVM[0].GasEstimator.BlockHistory.CheckInclusionBlocks = ptr[uint16](4) + ccfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.EIP1559DynamicFees = ptr(false) + c.GasEstimator.BlockHistory.BlockHistorySize = ptr[uint16](2) + c.GasEstimator.BlockHistory.CheckInclusionBlocks = ptr[uint16](4) }) - ccfg := evmtest.NewChainScopedConfig(t, cfg) ctx := tests.Context(t) txStore := cltest.NewTestTxStore(t, db) @@ -737,7 +728,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), ccfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient) ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0) // Create confirmer with necessary state - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), confirmerConfig{}, kst, txBuilder, lggr, stuckTxDetector, ht) servicetest.Run(t, ec) currentHead := int64(30) oldEnough := int64(15) @@ -762,12 +753,11 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing }) t.Run("should retry previous attempt if connectivity check failed for dynamic transactions", func(t *testing.T) { - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) - c.EVM[0].GasEstimator.BlockHistory.BlockHistorySize = ptr[uint16](2) - c.EVM[0].GasEstimator.BlockHistory.CheckInclusionBlocks = ptr[uint16](4) + ccfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.EIP1559DynamicFees = ptr(true) + c.GasEstimator.BlockHistory.BlockHistorySize = ptr[uint16](2) + c.GasEstimator.BlockHistory.CheckInclusionBlocks = ptr[uint16](4) }) - ccfg := evmtest.NewChainScopedConfig(t, cfg) ctx := tests.Context(t) txStore := cltest.NewTestTxStore(t, db) @@ -786,7 +776,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), ccfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient) ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), confirmerConfig{}, kst, txBuilder, lggr, stuckTxDetector, ht) servicetest.Run(t, ec) currentHead := int64(30) oldEnough := int64(15) @@ -815,16 +805,15 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) - }) txStore := cltest.NewTestTxStore(t, db) ctx := tests.Context(t) ethClient := clienttest.NewClientWithDefaultChainID(t) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.PriceMax = assets.GWei(500) + }) _, _ = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -833,7 +822,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Use a mock keystore for this test - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -882,13 +871,12 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Parallel() - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) - c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) - }) ctx := tests.Context(t) ethClient := clienttest.NewClientWithDefaultChainID(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.PriceMax = assets.GWei(500) + c.GasEstimator.BumpMin = assets.NewWeiI(0) + }) currentHead := int64(30) t.Run("does nothing if no transactions require bumping", func(t *testing.T) { @@ -897,7 +885,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) require.NoError(t, ec.RebroadcastWhereNecessary(ctx, currentHead)) }) @@ -917,7 +905,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }), mock.Anything).Return(nil, errors.New("signing error")).Once() // Use a mock keystore for this test - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) err := ec.RebroadcastWhereNecessary(ctx, currentHead) require.Error(t, err) @@ -936,7 +924,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, assets.NewWeiI(100)) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -956,7 +944,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) latestGasPrice := assets.GWei(20) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, latestGasPrice) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -982,7 +970,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 0, fromAddress, txmgrtypes.TxAttemptBroadcast) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) require.NoError(t, ec.RebroadcastWhereNecessary(ctx, currentHead)) var err error @@ -999,7 +987,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) latestGasPrice := assets.GWei(20) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, latestGasPrice) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1026,7 +1014,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) latestGasPrice := assets.GWei(20) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, latestGasPrice) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1057,7 +1045,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { latestGasPrice := assets.GWei(20) broadcastBlockNum := int64(25) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, broadcastBlockNum, latestGasPrice) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1108,7 +1096,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { latestGasPrice := assets.GWei(20) broadcastBlockNum := int64(25) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, broadcastBlockNum, latestGasPrice) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1135,16 +1123,15 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) priceMax := assets.GWei(30) - gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = priceMax + newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.PriceMax = priceMax }) - newCfg := evmtest.NewChainScopedConfig(t, gcfg) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) broadcastBlockNum := int64(25) currentAttemptPrice := priceMax.Sub(assets.GWei(1)) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, broadcastBlockNum, currentAttemptPrice) - ec := newEthConfirmer(t, txStore, ethClient, cfg, newCfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1167,15 +1154,14 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) priceMax := assets.GWei(30) - gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = priceMax + newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.PriceMax = priceMax }) - newCfg := evmtest.NewChainScopedConfig(t, gcfg) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) broadcastBlockNum := int64(25) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, broadcastBlockNum, priceMax) - ec := newEthConfirmer(t, txStore, ethClient, cfg, newCfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1197,16 +1183,15 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("EIP-1559: bumps using EIP-1559 rules when existing attempts are of type 0x2", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.BumpMin = assets.GWei(1) + newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.BumpMin = assets.GWei(1) }) - newCfg := evmtest.NewChainScopedConfig(t, gcfg) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, 0, fromAddress) err := txStore.UpdateTxAttemptBroadcastBeforeBlockNum(ctx, etx.ID, uint(25)) require.NoError(t, err) - ec := newEthConfirmer(t, txStore, ethClient, cfg, newCfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1229,16 +1214,15 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("EIP-1559: resubmits at the old price and does not create a new attempt if one of the bumped EIP-1559 transactions would have its tip cap exceed EVM.GasEstimator.PriceMax", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(1) + newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.PriceMax = assets.NewWeiI(1) }) - newCfg := evmtest.NewChainScopedConfig(t, gcfg) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, 0, fromAddress) err := txStore.UpdateTxAttemptBroadcastBeforeBlockNum(ctx, etx.ID, uint(25)) require.NoError(t, err) - ec := newEthConfirmer(t, txStore, ethClient, cfg, newCfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1259,17 +1243,16 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("EIP-1559: re-bumps attempt if initial bump is underpriced because the bumped gas price is insufficiently higher than the previous one", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.BumpMin = assets.GWei(1) + newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.BumpMin = assets.GWei(1) }) - newCfg := evmtest.NewChainScopedConfig(t, gcfg) // NOTE: This test case was empirically impossible when I tried it on eth mainnet (any EIP1559 transaction with a higher tip cap is accepted even if it's only 1 wei more) but appears to be possible on Polygon/Matic, probably due to poor design that applies the 10% minimum to the overall value (base fee + tip cap) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, 0, fromAddress) err := txStore.UpdateTxAttemptBroadcastBeforeBlockNum(ctx, etx.ID, uint(25)) require.NoError(t, err) - ec := newEthConfirmer(t, txStore, ethClient, cfg, newCfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -1296,14 +1279,13 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Parallel() db := testutils.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) - }) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.PriceMax = assets.GWei(500) + }) _, _ = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1318,7 +1300,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("terminally underpriced transaction with in_progress attempt is retried with more gas", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) originalBroadcastAt := time.Unix(1616509100, 0) etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, nonce, fromAddress, txmgrtypes.TxAttemptInProgress, originalBroadcastAt) @@ -1342,7 +1324,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in legacy mode", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -1374,7 +1356,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in EIP-1559 mode", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, kst, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -1422,7 +1404,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { // keyStates, err := ethKeyStore.GetStatesForKeys(keys) // require.NoError(t, err) - gconfig, config := newTestChainScopedConfig(t) + config := configtest.NewChainScopedConfig(t, nil) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -1438,7 +1420,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { insufficientEthError := errors.New("insufficient funds for gas * price + value") t.Run("saves attempt with state 'insufficient_eth' if eth node returns this error", func(t *testing.T) { - ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.GasPrice.ToInt().Int64()) @@ -1464,7 +1446,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("does not bump gas when previous error was 'out of eth', instead resubmits existing transaction", func(t *testing.T) { - ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.GasPrice.ToInt().Int64()) @@ -1489,7 +1471,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("saves the attempt as broadcast after node wallet has been topped up with sufficient balance", func(t *testing.T) { - ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.GasPrice.ToInt().Int64()) @@ -1517,11 +1499,10 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { depth := 2 etxCount := 4 - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.BumpTxDepth = ptr(uint32(depth)) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.BumpTxDepth = ptr(uint32(depth)) }) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) for i := 0; i < etxCount; i++ { n := nonce @@ -1546,9 +1527,6 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyStuckError(t *testing. t.Parallel() db := testutils.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) - }) txStore := cltest.NewTestTxStore(t, db) ctx := tests.Context(t) @@ -1556,10 +1534,12 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyStuckError(t *testing. ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.PriceMax = assets.GWei(500) + }) // Use a mock keystore for this test - ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -1603,7 +1583,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - gconfig, config := newTestChainScopedConfig(t) + config := configtest.NewChainScopedConfig(t, nil) mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) mustInsertInProgressEthTx(t, txStore, 0, fromAddress) etx1 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress) @@ -1614,7 +1594,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts one eth_tx if it falls within in nonce range", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -1629,7 +1609,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("uses default gas limit if overrideGasLimit is 0", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -1644,7 +1624,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts several eth_txes in nonce range", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && tx.GasPrice().Int64() == gasPriceWei.GasPrice.Int64() && tx.Gas() == overrideGasLimit @@ -1658,7 +1638,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("broadcasts zero transactions if eth_tx doesn't exist for that nonce", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(1) @@ -1684,7 +1664,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("zero transactions use default gas limit if override wasn't specified", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil) + ec := newEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(0) && tx.GasPrice().Int64() == gasPriceWei.GasPrice.Int64() && tx.Gas() == config.EVM().GasEstimator().LimitDefault() @@ -1716,18 +1696,17 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) { autoPurgeThreshold := uint32(5) autoPurgeMinAttempts := uint32(3) limitDefault := uint64(100) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.LimitDefault = ptr(limitDefault) - c.EVM[0].Transactions.AutoPurge.Enabled = ptr(true) - c.EVM[0].Transactions.AutoPurge.Threshold = ptr(autoPurgeThreshold) - c.EVM[0].Transactions.AutoPurge.MinAttempts = ptr(autoPurgeMinAttempts) + evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.GasEstimator.LimitDefault = ptr(limitDefault) + c.Transactions.AutoPurge.Enabled = ptr(true) + c.Transactions.AutoPurge.Threshold = ptr(autoPurgeThreshold) + c.Transactions.AutoPurge.MinAttempts = ptr(autoPurgeMinAttempts) }) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) ge := evmcfg.EVM().GasEstimator() txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), evmcfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient) ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database(), ethKeyStore, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), confirmerConfig{}, ethKeyStore, txBuilder, lggr, stuckTxDetector, ht) fn := func(ctx context.Context, id uuid.UUID, result interface{}, err error) error { require.ErrorContains(t, err, client.TerminallyStuckMsg) return nil @@ -1795,7 +1774,7 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) { func ptr[T any](t T) *T { return &t } -func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, gconfig chainlink.GeneralConfig, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { +func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { lggr := logger.Test(t) ge := config.EVM().GasEstimator() estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { @@ -1804,8 +1783,16 @@ func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Cl txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), config.EVM().Transactions().AutoPurge(), estimator, txStore, ethClient) ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), gconfig.Database(), ks, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), confirmerConfig{}, ks, txBuilder, lggr, stuckTxDetector, ht) ec.SetResumeCallback(fn) servicetest.Run(t, ec) return ec } + +var _ txmgrtypes.ConfirmerDatabaseConfig = confirmerConfig{} + +type confirmerConfig struct{} + +func (d confirmerConfig) DefaultQueryTimeout() time.Duration { + return 10 * time.Second +} diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 495260d0ca4..e23da197fda 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -23,12 +23,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/evm/assets" "github.com/smartcontractkit/chainlink/v2/evm/client" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" + "github.com/smartcontractkit/chainlink/v2/evm/config/configtest" + "github.com/smartcontractkit/chainlink/v2/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/evm/gas" "github.com/smartcontractkit/chainlink/v2/evm/testutils" "github.com/smartcontractkit/chainlink/v2/evm/types" @@ -373,10 +372,10 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - _, cfg := newTestChainScopedConfig(t) + cfg := configtest.NewChainScopedConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) chainID := ethClient.ConfiguredChainID() @@ -552,7 +551,7 @@ func TestORM_GetInProgressTxAttempts(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // insert etx with attempt @@ -572,7 +571,7 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) testutils.MustExec(t, db, `SET CONSTRAINTS fk_pipeline_runs_pruning_key DEFERRED`) @@ -605,7 +604,7 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { testutils.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr1.ID, minConfirmations, etx1.ID) // Callback to pipeline service completed. Should be ignored - run2 := cltest.MustInsertPipelineRunWithStatus(t, db, 0, pipeline.RunStatusCompleted, 0) + run2 := cltest.MustInsertPipelineRunWithStatus(t, db, 0, "completed", 0) tr2 := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run2.ID) etx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 4, 1, fromAddress) testutils.MustExec(t, db, `UPDATE evm.txes SET meta='{"FailOnRevert": false}'`) @@ -659,7 +658,7 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { func Test_FindTxWithIdempotencyKey(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - _, cfg := newTestChainScopedConfig(t) + cfg := configtest.NewChainScopedConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -787,7 +786,7 @@ func TestORM_FindEarliestUnconfirmedBroadcastTime(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("no unconfirmed eth txes", func(t *testing.T) { @@ -810,7 +809,7 @@ func TestORM_FindEarliestUnconfirmedTxAttemptBlock(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, fromAddress2 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -977,7 +976,7 @@ func TestORM_FindTxsRequiringGasBump(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) currentBlockNum := int64(10) @@ -1154,7 +1153,7 @@ func TestORM_FindNextUnstartedTransactionFromAddress(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1276,15 +1275,13 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { require.Len(t, etx.TxAttempts, 1) zero := commonconfig.MustNewDuration(time.Duration(0)) - evmCfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].Chain.Transactions.ReaperInterval = zero - c.EVM[0].Chain.Transactions.ReaperThreshold = zero - c.EVM[0].Chain.Transactions.ResendAfterThreshold = zero + ccfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { + c.Transactions.ReaperInterval = zero + c.Transactions.ReaperThreshold = zero + c.Transactions.ResendAfterThreshold = zero }) - - ccfg := evmtest.NewChainScopedConfig(t, evmCfg) evmTxmCfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) - ec := evmtest.NewEthClientMockWithDefaultChain(t) + ec := clienttest.NewClientWithDefaultChainID(t) txMgr := txmgr.NewEvmTxm(ec.ConfiguredChainID(), evmTxmCfg, ccfg.EVM().Transactions(), nil, logger.Test(t), nil, nil, nil, txStore, nil, nil, nil, nil, nil, nil) err := txMgr.XXXTestAbandon(fromAddress) // mark transaction as abandoned @@ -1346,7 +1343,7 @@ func TestORM_GetAbandonedTransactionsByBatch(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, enabled := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) enabledAddrs := []common.Address{enabled} @@ -1447,7 +1444,7 @@ func TestORM_HasInProgressTransaction(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("no in progress eth transaction", func(t *testing.T) { @@ -1632,7 +1629,7 @@ func TestORM_CreateTransaction(t *testing.T) { gasLimit := uint64(1000) payload := []byte{1, 2, 3} - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) t.Run("with queue under capacity inserts eth_tx", func(t *testing.T) { subject := uuid.New() @@ -1725,7 +1722,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := txmgr.NewTxStore(db, logger.Test(t)) ethKeyStore := cltest.NewKeyStore(t, db).Eth() - evmtest.NewEthClientMockWithDefaultChain(t) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("does not prune if queue has not exceeded capacity-1", func(t *testing.T) { diff --git a/core/chains/evm/txmgr/finalizer_test.go b/core/chains/evm/txmgr/finalizer_test.go index f5e423ab966..7fef240370d 100644 --- a/core/chains/evm/txmgr/finalizer_test.go +++ b/core/chains/evm/txmgr/finalizer_test.go @@ -27,10 +27,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/evm/client" "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" + "github.com/smartcontractkit/chainlink/v2/evm/config/configtest" "github.com/smartcontractkit/chainlink/v2/evm/testutils" "github.com/smartcontractkit/chainlink/v2/evm/types" "github.com/smartcontractkit/chainlink/v2/evm/utils" @@ -458,8 +457,8 @@ func TestFinalizer_ResumePendingRuns(t *testing.T) { func TestFinalizer_FetchAndStoreReceipts(t *testing.T) { t.Parallel() ctx := tests.Context(t) - cfg := configtest.NewTestGeneralConfig(t) - config := evmtest.NewChainScopedConfig(t, cfg) + + config := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) txmClient := txmgr.NewEvmTxmClient(ethClient, nil) rpcBatchSize := config.EVM().RPCDefaultBatchSize() diff --git a/core/chains/evm/txmgr/stuck_tx_detector_test.go b/core/chains/evm/txmgr/stuck_tx_detector_test.go index 38fe5674a8c..7c3eb302311 100644 --- a/core/chains/evm/txmgr/stuck_tx_detector_test.go +++ b/core/chains/evm/txmgr/stuck_tx_detector_test.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/v2/evm/config/configtest" txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" @@ -108,7 +109,7 @@ func TestStuckTxDetector_FindPotentialStuckTxs(t *testing.T) { t.Parallel() db := testutils.NewSqlxDB(t) - _, config := newTestChainScopedConfig(t) + config := configtest.NewChainScopedConfig(t, nil) txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() ctx := tests.Context(t) diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 2246bb6b64e..001ead9255e 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -34,8 +34,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/evm/client" "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" @@ -541,8 +539,8 @@ func TestTxm_Reset(t *testing.T) { // Lots of boilerplate setup since we actually want to test start/stop of EthBroadcaster/EthConfirmer db := testutils.NewSqlxDB(t) - gcfg := configtest.NewTestGeneralConfig(t) - cfg := evmtest.NewChainScopedConfig(t, gcfg) + + _, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) kst := cltest.NewKeyStore(t, db) _, addr := cltest.RandomKey{}.MustInsert(t, kst.Eth()) @@ -558,14 +556,14 @@ func TestTxm_Reset(t *testing.T) { } ethClient := clienttest.NewClientWithDefaultChainID(t) - ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil) + ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil).Maybe() ethClient.On("BatchCallContextAll", mock.Anything, mock.Anything).Return(nil).Maybe() ethClient.On("PendingNonceAt", mock.Anything, addr).Return(uint64(128), nil).Maybe() ethClient.On("PendingNonceAt", mock.Anything, addr2).Return(uint64(44), nil).Maybe() - estimator, err := gas.NewEstimator(logger.Test(t), ethClient, cfg.EVM().ChainType(), ethClient.ConfiguredChainID(), cfg.EVM().GasEstimator(), nil) + estimator, err := gas.NewEstimator(logger.Test(t), ethClient, evmConfig.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(t, err) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), gcfg.Database(), gcfg.Database().Listener(), kst.Eth()) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth()) require.NoError(t, err) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, addr2) @@ -611,8 +609,8 @@ func TestTxm_GetTransactionStatus(t *testing.T) { txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() feeLimit := uint64(10_000) - gcfg := configtest.NewTestGeneralConfig(t) - cfg := evmtest.NewChainScopedConfig(t, gcfg) + + _, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) h99 := &evmtypes.Head{ Hash: utils.NewHash(), @@ -625,7 +623,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { } head.Parent.Store(h99) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil).Maybe() ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil).Once() ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head.Parent.Load(), nil).Once() @@ -634,7 +632,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { feeEstimator.On("Start", mock.Anything).Return(nil).Once() feeEstimator.On("Close", mock.Anything).Return(nil).Once() feeEstimator.On("OnNewLongestChain", mock.Anything, mock.Anything).Once() - txm, err := makeTestEvmTxm(t, db, ethClient, feeEstimator, cfg.EVM(), cfg.EVM().GasEstimator(), cfg.EVM().Transactions(), gcfg.Database(), gcfg.Database().Listener(), ethKeyStore) + txm, err := makeTestEvmTxm(t, db, ethClient, feeEstimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), ethKeyStore) require.NoError(t, err) servicetest.Run(t, txm) diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 721de61e770..8d3e2251bb0 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -125,12 +125,6 @@ func (e errChainDisabled) Error() string { return fmt.Sprintf("cannot create new chain with ID %s, the chain is disabled", e.ChainID.String()) } -// TODO BCF-2509 what is this and does it need the entire app config? -type AppConfig interface { - EVMRPCEnabled() bool - toml.HasEVMConfigs -} - type FeatureConfig interface { LogPoller() bool } @@ -142,7 +136,7 @@ type ChainRelayOpts struct { } type ChainOpts struct { - AppConfig AppConfig + ChainConfigs toml.EVMConfigs DatabaseConfig txmgr.DatabaseConfig FeatureConfig FeatureConfig ListenerConfig txmgr.ListenerConfig @@ -164,8 +158,8 @@ type ChainOpts struct { func (o ChainOpts) Validate() error { var err error - if o.AppConfig == nil { - err = errors.Join(err, errors.New("nil AppConfig")) + if o.ChainConfigs == nil { + err = errors.Join(err, errors.New("nil ChainConfigs")) } if o.DatabaseConfig == nil { err = errors.Join(err, errors.New("nil DatabaseConfig")) @@ -195,11 +189,10 @@ func NewTOMLChain(ctx context.Context, chain *toml.EVMConfig, opts ChainRelayOpt return nil, err } chainID := chain.ChainID - l := opts.Logger.With("evmChainID", chainID.String()) if !chain.IsEnabled() { return nil, errChainDisabled{ChainID: chainID} } - cfg := config.NewTOMLChainScopedConfig(chain, l) + cfg := config.NewTOMLChainScopedConfig(chain) // note: per-chain validation is not necessary at this point since everything is checked earlier on boot. return newChain(ctx, cfg, chain.Nodes, opts, clientsByChainID) } @@ -209,7 +202,7 @@ func newChain(ctx context.Context, cfg *config.ChainScoped, nodes []*toml.Node, l := opts.Logger var cl client.Client var err error - if !opts.AppConfig.EVMRPCEnabled() { + if !opts.ChainConfigs.RPCEnabled() { cl = client.NewNullClient(chainID, l) } else if opts.GenEthClient == nil { cl, err = client.NewEvmClient(cfg.EVM().NodePool(), cfg.EVM(), cfg.EVM().NodePool().Errors(), l, chainID, nodes, cfg.EVM().ChainType()) @@ -223,7 +216,7 @@ func newChain(ctx context.Context, cfg *config.ChainScoped, nodes []*toml.Node, headBroadcaster := headtracker.NewHeadBroadcaster(l) headSaver := headtracker.NullSaver var headTracker httypes.HeadTracker - if !opts.AppConfig.EVMRPCEnabled() { + if !opts.ChainConfigs.RPCEnabled() { headTracker = headtracker.NullTracker } else if opts.GenHeadTracker == nil { var orm headtracker.ORM @@ -267,7 +260,7 @@ func newChain(ctx context.Context, cfg *config.ChainScoped, nodes []*toml.Node, // note: gas estimator is started as a part of the txm var txm txmgr.TxManager //nolint:gocritic // ignoring suggestion to convert to switch statement - if !opts.AppConfig.EVMRPCEnabled() { + if !opts.ChainConfigs.RPCEnabled() { txm = &txmgr.NullTxManager{ErrMsg: fmt.Sprintf("Ethereum is disabled for chain %d", chainID)} } else if !cfg.EVM().Transactions().Enabled() { txm = &txmgr.NullTxManager{ErrMsg: fmt.Sprintf("TXM disabled for chain %d", chainID)} @@ -287,13 +280,13 @@ func newChain(ctx context.Context, cfg *config.ChainScoped, nodes []*toml.Node, } var balanceMonitor monitor.BalanceMonitor - if opts.AppConfig.EVMRPCEnabled() && cfg.EVM().BalanceMonitor().Enabled() { + if opts.ChainConfigs.RPCEnabled() && cfg.EVM().BalanceMonitor().Enabled() { balanceMonitor = monitor.NewBalanceMonitor(cl, opts.KeyStore, l) headBroadcaster.Subscribe(balanceMonitor) } var logBroadcaster log.Broadcaster - if !opts.AppConfig.EVMRPCEnabled() { + if !opts.ChainConfigs.RPCEnabled() { logBroadcaster = &log.NullBroadcaster{ErrMsg: fmt.Sprintf("Ethereum is disabled for chain %d", chainID)} } else if !cfg.EVM().LogBroadcasterEnabled() { logBroadcaster = &log.NullBroadcaster{ErrMsg: fmt.Sprintf("LogBroadcaster disabled for chain %d", chainID)} diff --git a/core/chains/legacyevm/chain_test.go b/core/chains/legacyevm/chain_test.go index be5a8b76917..16553c52c98 100644 --- a/core/chains/legacyevm/chain_test.go +++ b/core/chains/legacyevm/chain_test.go @@ -38,7 +38,7 @@ func TestChainOpts_Validate(t *testing.T) { { name: "valid", opts: legacyevm.ChainOpts{ - AppConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), ListenerConfig: cfg.Database().Listener(), FeatureConfig: cfg.Feature(), diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 144bd4a953e..f182875d2da 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -257,7 +257,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G evmFactoryCfg := chainlink.EVMFactoryConfig{ CSAETHKeystore: keyStore, ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), ListenerConfig: cfg.Database().Listener(), FeatureConfig: cfg.Feature(), diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 331432299a8..5e86b17c575 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -9,12 +9,18 @@ import ( "testing" "time" + gethTypes "github.com/ethereum/go-ethereum/core/types" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" pgcommon "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/pg" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-framework/multinode" - evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/capabilities" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -30,18 +36,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" chainlinkmocks "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/mocks" + evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" "github.com/smartcontractkit/chainlink/v2/plugins" - - gethTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/urfave/cli" ) func genTestEVMRelayers(t *testing.T, cfg chainlink.GeneralConfig, ds sqlutil.DataSource, ks evmrelayer.CSAETHKeystore) *chainlink.CoreRelayerChainInteroperators { @@ -54,7 +55,7 @@ func genTestEVMRelayers(t *testing.T, cfg chainlink.GeneralConfig, ds sqlutil.Da relayers, err := chainlink.NewCoreRelayerChainInteroperators(chainlink.InitEVM(testutils.Context(t), f, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), ListenerConfig: cfg.Database().Listener(), FeatureConfig: cfg.Feature(), @@ -291,7 +292,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { app.On("GetKeyStore").Return(keyStore) app.On("ID").Maybe().Return(uuid.New()) app.On("GetConfig").Return(config) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) legacy := cltest.NewLegacyChainsWithMockChain(t, ethClient, config) mockRelayerChainInteroperators := &chainlinkmocks.FakeRelayerChainInteroperators{EVMChains: legacy} @@ -373,7 +374,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { app.On("GetKeyStore").Return(keyStore) app.On("ID").Maybe().Return(uuid.New()) app.On("GetConfig").Return(config) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("Dial", mock.Anything).Return(nil) legacy := cltest.NewLegacyChainsWithMockChain(t, ethClient, config) @@ -451,7 +452,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { app.On("GetDB").Maybe().Return(sqlxDB) app.On("GetKeyStore").Return(keyStore) app.On("ID").Maybe().Return(uuid.New()) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("Dial", mock.Anything).Return(nil) legacy := cltest.NewLegacyChainsWithMockChain(t, ethClient, config) diff --git a/core/config/app_config.go b/core/config/app_config.go index 4ce8873bb96..d4ef27b6305 100644 --- a/core/config/app_config.go +++ b/core/config/app_config.go @@ -20,7 +20,6 @@ type AppConfig interface { ShutdownGracePeriod() time.Duration InsecureFastScrypt() bool EVMEnabled() bool - EVMRPCEnabled() bool CosmosEnabled() bool SolanaEnabled() bool StarkNetEnabled() bool diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 132dd60a8f9..ae3b8c5e243 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -436,7 +436,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn evmOpts := chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), ListenerConfig: cfg.Database().Listener(), FeatureConfig: cfg.Feature(), diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index b2ad81bb2c2..24922715eda 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -28,6 +28,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/web" evmclient "github.com/smartcontractkit/chainlink/v2/evm/client" + "github.com/smartcontractkit/chainlink/v2/evm/config/toml" evmtypes "github.com/smartcontractkit/chainlink/v2/evm/types" ) @@ -398,7 +399,7 @@ func (m MockPasswordPrompter) Prompt() string { return m.Password } -func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg legacyevm.AppConfig) legacyevm.LegacyChainContainer { +func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg toml.HasEVMConfigs) legacyevm.LegacyChainContainer { ch := new(evmmocks.Chain) ch.On("Client").Return(ethClient) ch.On("Logger").Return(logger.TestLogger(t)) @@ -410,7 +411,7 @@ func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg return NewLegacyChainsWithChain(ch, cfg) } -func NewLegacyChainsWithMockChainAndTxManager(t testing.TB, ethClient evmclient.Client, cfg legacyevm.AppConfig, txm txmgr.TxManager) legacyevm.LegacyChainContainer { +func NewLegacyChainsWithMockChainAndTxManager(t testing.TB, ethClient evmclient.Client, cfg toml.HasEVMConfigs, txm txmgr.TxManager) legacyevm.LegacyChainContainer { ch := new(evmmocks.Chain) ch.On("Client").Return(ethClient) ch.On("Logger").Return(logger.TestLogger(t)) @@ -422,7 +423,7 @@ func NewLegacyChainsWithMockChainAndTxManager(t testing.TB, ethClient evmclient. return NewLegacyChainsWithChain(ch, cfg) } -func NewLegacyChainsWithChain(ch legacyevm.Chain, cfg legacyevm.AppConfig) legacyevm.LegacyChainContainer { +func NewLegacyChainsWithChain(ch legacyevm.Chain, cfg toml.HasEVMConfigs) legacyevm.LegacyChainContainer { m := map[string]legacyevm.Chain{ch.ID().String(): ch} return legacyevm.NewLegacyChains(m, cfg.EVMConfigs()) } diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index c69ce1defc5..929a9b22aaf 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -1286,7 +1286,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { require.NoError(t, kst.Unlock(ctx, cltest.Password)) chainsAndConfig := evmtest.NewLegacyChainsAndConfig(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 685736827db..6bfab4166c5 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -36,7 +36,7 @@ import ( ubig "github.com/smartcontractkit/chainlink/v2/evm/utils/big" ) -func NewChainScopedConfig(t testing.TB, cfg legacyevm.AppConfig) evmconfig.ChainScopedConfig { +func NewChainScopedConfig(t testing.TB, cfg configtoml.HasEVMConfigs) evmconfig.ChainScopedConfig { var evmCfg *configtoml.EVMConfig if len(cfg.EVMConfigs()) > 0 { evmCfg = cfg.EVMConfigs()[0] @@ -48,14 +48,14 @@ func NewChainScopedConfig(t testing.TB, cfg legacyevm.AppConfig) evmconfig.Chain } } - return evmconfig.NewTOMLChainScopedConfig(evmCfg, logger.TestLogger(t)) + return evmconfig.NewTOMLChainScopedConfig(evmCfg) } type TestChainOpts struct { Client evmclient.Client LogBroadcaster log.Broadcaster LogPoller logpoller.LogPoller - GeneralConfig legacyevm.AppConfig + ChainConfigs configtoml.EVMConfigs DatabaseConfig txmgr.DatabaseConfig FeatureConfig legacyevm.FeatureConfig ListenerConfig txmgr.ListenerConfig @@ -90,7 +90,7 @@ func NewChainOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainRelayOpts Logger: lggr, KeyStore: testopts.KeyStore, ChainOpts: legacyevm.ChainOpts{ - AppConfig: testopts.GeneralConfig, + ChainConfigs: testopts.ChainConfigs, DatabaseConfig: testopts.DatabaseConfig, ListenerConfig: testopts.ListenerConfig, FeatureConfig: testopts.FeatureConfig, @@ -103,7 +103,7 @@ func NewChainOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainRelayOpts if testopts.Client != nil { return testopts.Client } - return evmclient.NewNullClient(MustGetDefaultChainID(t, testopts.GeneralConfig.EVMConfigs()), logger.TestLogger(t)) + return evmclient.NewNullClient(MustGetDefaultChainID(t, testopts.ChainConfigs), logger.TestLogger(t)) } if testopts.LogBroadcaster != nil { opts.GenLogBroadcaster = func(*big.Int) log.Broadcaster { @@ -301,10 +301,12 @@ func nodeStatus(n *configtoml.Node, chainID string) (types.NodeStatus, error) { return s, nil } +// Deprecated: use clienttest.NewClient func NewEthClientMock(t *testing.T) *clienttest.Client { return clienttest.NewClient(t) } +// Deprecated: use clienttest.NewClientWithDefaultChainID func NewEthClientMockWithDefaultChain(t *testing.T) *clienttest.Client { c := NewEthClientMock(t) c.On("ConfiguredChainID").Return(testutils.FixtureChainID).Maybe() diff --git a/core/internal/testutils/evmtest/v2/evmtest.go b/core/internal/testutils/evmtest/v2/evmtest.go index 53666768442..5f8d93f851c 100644 --- a/core/internal/testutils/evmtest/v2/evmtest.go +++ b/core/internal/testutils/evmtest/v2/evmtest.go @@ -3,7 +3,6 @@ package v2 import ( "testing" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/evm/config" "github.com/smartcontractkit/chainlink/v2/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/evm/utils/big" @@ -17,5 +16,5 @@ func ChainArbitrumRinkeby(t *testing.T) config.ChainScopedConfig { return scoped func scopedConfig(t *testing.T, chainID int64) config.ChainScopedConfig { id := big.NewI(chainID) evmCfg := toml.EVMConfig{ChainID: id, Chain: toml.Defaults(id)} - return config.NewTOMLChainScopedConfig(&evmCfg, logger.TestLogger(t)) + return config.NewTOMLChainScopedConfig(&evmCfg) } diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index 5b89794eb6e..9aa589a98c2 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -19,18 +19,19 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" "github.com/smartcontractkit/chainlink/v2/evm/types" ) func TestStoreRotatesFromAddresses(t *testing.T) { ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) cfg := configtest.NewTestGeneralConfig(t) kst := cltest.NewKeyStore(t, db) require.NoError(t, kst.Unlock(ctx, cltest.Password)) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index be32bd21e66..8f006d6a708 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -49,7 +49,7 @@ func createTestDelegate(t *testing.T) (*blockhashstore.Delegate, *testData) { t.Helper() lggr, logs := logger.TestLoggerObserved(t, zapcore.DebugLevel) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = func(b bool) *bool { return &b }(true) }) @@ -63,7 +63,7 @@ func createTestDelegate(t *testing.T) (*blockhashstore.Delegate, *testData) { legacyChains := evmtest.NewLegacyChains( t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 3e4649e0f40..e92847ccb34 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -622,7 +622,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { ) // Flux monitor requires ethereum just to boot, silence errors with a null delegate - if !cfg.EVMRPCEnabled() { + if !cfg.EVMConfigs().RPCEnabled() { delegates[job.FluxMonitor] = &job.NullDelegate{Type: job.FluxMonitor} } else { delegates[job.FluxMonitor] = fluxmonitorv2.NewDelegate( diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index ea27d28d28b..65d9126b3d6 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -195,6 +195,9 @@ func (o *GeneralConfigOpts) parse() (err error) { } func (g *generalConfig) EVMConfigs() evmcfg.EVMConfigs { + if g.c.EVM == nil { + return evmcfg.EVMConfigs{} // return empty to pass nil check + } return g.c.EVM } @@ -316,17 +319,6 @@ func (g *generalConfig) EVMEnabled() bool { return false } -func (g *generalConfig) EVMRPCEnabled() bool { - for _, c := range g.c.EVM { - if c.IsEnabled() { - if len(c.Nodes) > 0 { - return true - } - } - } - return false -} - func (g *generalConfig) SolanaEnabled() bool { for _, c := range g.c.Solana { if c.IsEnabled() { diff --git a/core/services/chainlink/config_general_test.go b/core/services/chainlink/config_general_test.go index 3f02b880baf..22a5a131e5a 100644 --- a/core/services/chainlink/config_general_test.go +++ b/core/services/chainlink/config_general_test.go @@ -23,7 +23,7 @@ func TestTOMLGeneralConfig_Defaults(t *testing.T) { config, err := GeneralConfigOpts{}.New() require.NoError(t, err) assert.Equal(t, (*url.URL)(nil), config.WebServer().BridgeResponseURL()) - assert.False(t, config.EVMRPCEnabled()) + assert.False(t, config.EVMConfigs().RPCEnabled()) assert.False(t, config.EVMEnabled()) assert.False(t, config.CosmosEnabled()) assert.False(t, config.SolanaEnabled()) diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index 44b272ba93a..007f1e3e2db 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -602,51 +602,6 @@ func (_c *GeneralConfig_EVMEnabled_Call) RunAndReturn(run func() bool) *GeneralC return _c } -// EVMRPCEnabled provides a mock function with no fields -func (_m *GeneralConfig) EVMRPCEnabled() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for EVMRPCEnabled") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// GeneralConfig_EVMRPCEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EVMRPCEnabled' -type GeneralConfig_EVMRPCEnabled_Call struct { - *mock.Call -} - -// EVMRPCEnabled is a helper method to define mock.On call -func (_e *GeneralConfig_Expecter) EVMRPCEnabled() *GeneralConfig_EVMRPCEnabled_Call { - return &GeneralConfig_EVMRPCEnabled_Call{Call: _e.mock.On("EVMRPCEnabled")} -} - -func (_c *GeneralConfig_EVMRPCEnabled_Call) Run(run func()) *GeneralConfig_EVMRPCEnabled_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *GeneralConfig_EVMRPCEnabled_Call) Return(_a0 bool) *GeneralConfig_EVMRPCEnabled_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *GeneralConfig_EVMRPCEnabled_Call) RunAndReturn(run func() bool) *GeneralConfig_EVMRPCEnabled_Call { - _c.Call.Return(run) - return _c -} - // Feature provides a mock function with no fields func (_m *GeneralConfig) Feature() config.Feature { ret := _m.Called() diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index a3e9e2ad205..379bc658b0b 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -128,7 +128,7 @@ func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfi op.loopRelayers[id] = a legacyMap[id.ChainID] = a.Chain() } - op.legacyChains.EVMChains = legacyevm.NewLegacyChains(legacyMap, config.AppConfig.EVMConfigs()) + op.legacyChains.EVMChains = legacyevm.NewLegacyChains(legacyMap, config.ChainConfigs) return nil } } diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 26d6442132f..3fb98900b80 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -213,7 +213,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { initFuncs: []chainlink.CoreRelayerChainInitFunc{ chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), ListenerConfig: cfg.Database().Listener(), FeatureConfig: cfg.Feature(), @@ -289,7 +289,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { TOMLConfigs: cfg.SolanaConfigs()}), chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), ListenerConfig: cfg.Database().Listener(), FeatureConfig: cfg.Feature(), diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 80469a03636..4116ce57732 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -33,11 +33,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" pipeline_mocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" ubig "github.com/smartcontractkit/chainlink/v2/evm/utils/big" ) func TestDelegate_ServicesForSpec(t *testing.T) { - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) runner := pipeline_mocks.NewRunner(t) db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -46,7 +47,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { keyStore := cltest.NewKeyStore(t, db) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), @@ -84,7 +85,7 @@ type DirectRequestUniverse struct { } func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfig, specF func(spec *job.Job)) *DirectRequestUniverse { - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) broadcaster := log_mocks.NewBroadcaster(t) runner := pipeline_mocks.NewRunner(t) broadcaster.On("AddDependents", 1) @@ -94,7 +95,7 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index 0b042e98d79..f22d3a72c9d 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -1736,7 +1736,7 @@ func createJob(t *testing.T, db *sqlx.DB, externalJobID uuid.UUID) *job.Job { pipelineORM = pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) bridgeORM = bridges.NewORM(db) legacyChains = evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 055423c1dc9..24738680fb3 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -226,7 +226,7 @@ func setupTestServiceCfg(t *testing.T, overrideCfg func(c *chainlink.Config, s * keyStore := new(ksmocks.Master) ethKeyStore := cltest.NewKeyStore(t, db).Eth() legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: gcfg, + ChainConfigs: gcfg.EVMConfigs(), DatabaseConfig: gcfg.Database(), FeatureConfig: gcfg.Feature(), ListenerConfig: gcfg.Database().Listener(), diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 765c1908009..5cbab946b45 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -44,6 +44,7 @@ import ( sync_mocks "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" ) type FunctionsListenerUniverse struct { @@ -78,7 +79,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) }) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) broadcaster := log_mocks.NewBroadcaster(t) broadcaster.On("AddDependents", 1) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) @@ -86,7 +87,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe db := pgtest.NewSqlxDB(t) kst := cltest.NewKeyStore(t, db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/headreporter/prometheus_reporter_test.go b/core/services/headreporter/prometheus_reporter_test.go index ea8ffa732f8..a6a728738ba 100644 --- a/core/services/headreporter/prometheus_reporter_test.go +++ b/core/services/headreporter/prometheus_reporter_test.go @@ -17,10 +17,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/headreporter" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" "github.com/smartcontractkit/chainlink/v2/evm/gas" ) @@ -121,7 +121,7 @@ func Test_PrometheusReporter(t *testing.T) { func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainContainer { config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) keyStore := cltest.NewKeyStore(t, db).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) estimator, err := gas.NewEstimator(logger.TestLogger(t), ethClient, config.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(t, err) lggr := logger.TestLogger(t) @@ -157,7 +157,7 @@ func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainCon } func newLegacyChainContainerWithNullTxm(t *testing.T) legacyevm.LegacyChainContainer { - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) txm := &txmgr.NullTxManager{ErrMsg: fmt.Sprintf("TXM disabled for chain %d", ethClient.ConfiguredChainID())} cfg := configtest.NewGeneralConfig(t, nil) return cltest.NewLegacyChainsWithMockChainAndTxManager(t, ethClient, cfg, txm) diff --git a/core/services/job/helpers_test.go b/core/services/job/helpers_test.go index 6dd72b3d759..fae03ed6d43 100644 --- a/core/services/job/helpers_test.go +++ b/core/services/job/helpers_test.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" ) const ( @@ -211,12 +212,12 @@ func makeMinimalHTTPOracleSpec(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralC s := fmt.Sprintf(minimalNonBootstrapTemplate, contractAddress, transmitterAddress, keyBundle, fetchUrl, timeout) keyStore := cltest.NewKeyStore(t, db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), DB: db, - Client: evmtest.NewEthClientMockWithDefaultChain(t), + Client: clienttest.NewClientWithDefaultChainID(t), KeyStore: keyStore.Eth(), }) _, err := ocr.ValidatedOracleSpecToml(cfg, legacyChains, s) diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 6edf76118ce..eb0a7d23ce7 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -377,7 +377,7 @@ func TestORM_DeleteJob_DeletesAssociatedRecords(t *testing.T) { _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -803,7 +803,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { JobID: externalJobID.UUID.String(), }) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -1080,7 +1080,7 @@ func Test_FindJobs(t *testing.T) { _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -1171,7 +1171,7 @@ func Test_FindJob(t *testing.T) { externalJobID := uuid.New() _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -1409,7 +1409,7 @@ func Test_FindPipelineRuns(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -1479,7 +1479,7 @@ func Test_PipelineRunsByJobID(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -1548,7 +1548,7 @@ func Test_FindPipelineRunIDsByJobID(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -1669,7 +1669,7 @@ func Test_FindPipelineRunsByIDs(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -1855,7 +1855,7 @@ func Test_CountPipelineRunsByJobID(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index efc30299d7d..ff24995cec9 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -21,6 +21,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" ) func clearJobsDb(t *testing.T, db *sqlx.DB) { @@ -155,11 +156,11 @@ func TestPipelineORM_Integration(t *testing.T) { orm := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), - Client: evmtest.NewEthClientMockWithDefaultChain(t), + Client: clienttest.NewClientWithDefaultChainID(t), DB: db, KeyStore: ethKeyStore, }) diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index 1caa1461dc8..03f71e6cf09 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -86,7 +86,7 @@ func TestRunner(t *testing.T) { legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ DB: db, Client: ethClient, - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -570,7 +570,7 @@ answer1 [type=median index=0]; legacyChains2 := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ DB: db, Client: ethClient, - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index b28abcc9208..7e3f634228e 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -101,7 +101,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ DB: db, Client: ethClient, - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), @@ -286,7 +286,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { testopts := evmtest.TestChainOpts{ DB: db, Client: ethClient, - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), diff --git a/core/services/keeper/registry1_1_synchronizer_test.go b/core/services/keeper/registry1_1_synchronizer_test.go index b5d5bae5948..2ec2b18e88d 100644 --- a/core/services/keeper/registry1_1_synchronizer_test.go +++ b/core/services/keeper/registry1_1_synchronizer_test.go @@ -18,7 +18,6 @@ import ( registry1_1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" @@ -73,7 +72,7 @@ func mockRegistry1_1( func Test_LogListenerOpts1_1(t *testing.T) { db := pgtest.NewSqlxDB(t) korm := keeper.NewORM(db, logger.TestLogger(t)) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) j := cltest.MustInsertKeeperJob(t, db, korm, cltest.NewEIP55Address(), cltest.NewEIP55Address()) contractAddress := j.KeeperSpec.ContractAddress.Address() diff --git a/core/services/keeper/registry1_2_synchronizer_test.go b/core/services/keeper/registry1_2_synchronizer_test.go index 81af282d8c9..e7d915d565c 100644 --- a/core/services/keeper/registry1_2_synchronizer_test.go +++ b/core/services/keeper/registry1_2_synchronizer_test.go @@ -17,7 +17,6 @@ import ( registry1_2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" @@ -95,7 +94,7 @@ func mockRegistry1_2( func Test_LogListenerOpts1_2(t *testing.T) { db := pgtest.NewSqlxDB(t) korm := keeper.NewORM(db, logger.TestLogger(t)) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) j := cltest.MustInsertKeeperJob(t, db, korm, cltest.NewEIP55Address(), cltest.NewEIP55Address()) contractAddress := j.KeeperSpec.ContractAddress.Address() diff --git a/core/services/keeper/registry1_3_synchronizer_test.go b/core/services/keeper/registry1_3_synchronizer_test.go index dd4be5f3593..210b7092fbb 100644 --- a/core/services/keeper/registry1_3_synchronizer_test.go +++ b/core/services/keeper/registry1_3_synchronizer_test.go @@ -18,7 +18,6 @@ import ( registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" @@ -97,7 +96,7 @@ func mockRegistry1_3( func Test_LogListenerOpts1_3(t *testing.T) { db := pgtest.NewSqlxDB(t) korm := keeper.NewORM(db, logger.TestLogger(t)) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) j := cltest.MustInsertKeeperJob(t, db, korm, cltest.NewEIP55Address(), cltest.NewEIP55Address()) contractAddress := j.KeeperSpec.ContractAddress.Address() diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index 8a6b01b3394..34fff6095ca 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -38,7 +38,7 @@ func setupRegistrySync(t *testing.T, version keeper.RegistryVersion) ( db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) korm := keeper.NewORM(db, logger.TestLogger(t)) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) keyStore := cltest.NewKeyStore(t, db) lbMock := logmocks.NewBroadcaster(t) lbMock.On("AddDependents", 1).Maybe() @@ -47,7 +47,7 @@ func setupRegistrySync(t *testing.T, version keeper.RegistryVersion) ( DB: db, Client: ethClient, LogBroadcaster: lbMock, - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index bd2d7640f96..3a881d52265 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -85,7 +85,7 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain DB: db, Client: ethClient, KeyStore: keyStore.Eth(), - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index e55429d45cf..f98db3913dc 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -47,7 +47,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { txManager := txmmocks.NewMockEvmTxManager(t) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ DB: db, - GeneralConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go index fde3f5e41c9..881b1199bb8 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go @@ -444,7 +444,7 @@ func setupNodeCCIP( mailMon := mailbox.NewMonitor("CCIP", lggr.Named("Mailbox")) evmOpts := chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), ListenerConfig: config.Database().Listener(), FeatureConfig: config.Feature(), diff --git a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go index 6747d5bc1e7..5c556935a69 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go @@ -444,7 +444,7 @@ func setupNodeCCIP( mailMon := mailbox.NewMonitor("CCIP", lggr.Named("Mailbox")) evmOpts := chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: config, + ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), ListenerConfig: config.Database().Listener(), FeatureConfig: config.Feature(), diff --git a/core/services/pipeline/runner_test.go b/core/services/pipeline/runner_test.go index c9b3e1ed6ff..7b636534513 100644 --- a/core/services/pipeline/runner_test.go +++ b/core/services/pipeline/runner_test.go @@ -40,7 +40,7 @@ import ( func newRunner(t testing.TB, db *sqlx.DB, bridgeORM bridges.ORM, cfg chainlink.GeneralConfig) (pipeline.Runner, *mocks.ORM) { ethKeyStore := cltest.NewKeyStore(t, db).Eth() legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), @@ -516,7 +516,7 @@ func Test_PipelineRunner_HandleFaultsPersistRun(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db).Eth() legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), @@ -562,7 +562,7 @@ func Test_PipelineRunner_ExecuteAndInsertFinishedRun_SavingTheSpec(t *testing.T) cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db).Eth() legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), @@ -1038,7 +1038,7 @@ func Test_PipelineRunner_ExecuteRun(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db).Eth() legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/pipeline/task.eth_call_test.go b/core/services/pipeline/task.eth_call_test.go index 9e87fe5c19c..920964e5e48 100644 --- a/core/services/pipeline/task.eth_call_test.go +++ b/core/services/pipeline/task.eth_call_test.go @@ -314,7 +314,7 @@ func TestETHCallTask(t *testing.T) { if test.expectedErrorCause != nil || test.expectedErrorContains != "" { legacyChains = evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ DB: db, - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index e3864a41dca..0e1e96593fc 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -580,7 +580,7 @@ func TestETHTxTask(t *testing.T) { legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ DB: db, - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index 8b7e79c1fc5..2a5199de851 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -43,7 +43,7 @@ func NewLegacyChains(ctx context.Context, opts legacyevm.ChainRelayOpts) (result unique := make(map[string]struct{}) - evmConfigs := opts.AppConfig.EVMConfigs() + evmConfigs := opts.ChainConfigs var enabled []*toml.EVMConfig for i, cfg := range evmConfigs { _, alreadyExists := unique[cfg.ChainID.String()] @@ -81,5 +81,5 @@ func NewLegacyChains(ctx context.Context, opts legacyevm.ChainRelayOpts) (result func NewLegacyChainsAndConfig(ctx context.Context, opts legacyevm.ChainRelayOpts) (*LegacyChainsAndConfig, error) { result, err := NewLegacyChains(ctx, opts) // always return because it's accumulating errors - return &LegacyChainsAndConfig{result, opts.AppConfig.EVMConfigs()}, err + return &LegacyChainsAndConfig{result, opts.ChainConfigs}, err } diff --git a/core/services/relay/evm/relayer_extender_test.go b/core/services/relay/evm/relayer_extender_test.go index 9a65b486da7..0bda7825c71 100644 --- a/core/services/relay/evm/relayer_extender_test.go +++ b/core/services/relay/evm/relayer_extender_test.go @@ -38,7 +38,7 @@ func TestChainRelayExtenders(t *testing.T) { opts := evmtest.NewChainOpts(t, evmtest.TestChainOpts{ DB: db, KeyStore: kst.Eth(), - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index cebf2446309..6f8d4cfc714 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -92,7 +92,7 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv KeyStore: ks.Eth(), Client: ec, DB: db, - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index d06ee65278c..fd73a3e7504 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -2107,7 +2107,7 @@ func TestStartingCountsV1(t *testing.T) { KeyStore: ks.Eth(), Client: ec, DB: db, - GeneralConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index b3b9dd40282..0a58887a361 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -14,15 +14,14 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" - txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -30,13 +29,14 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" "github.com/smartcontractkit/chainlink/v2/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/evm/types" ) func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.Master) txmgrcommon.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] { _, _, evmConfig := txmgr.MakeTestConfigs(t) - ec := evmtest.NewEthClientMockWithDefaultChain(t) + ec := clienttest.NewClientWithDefaultChainID(t) txmConfig := txmgr.NewEvmTxmConfig(evmConfig) txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, nil, txStore, nil, nil, nil, nil, nil, nil) diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index 78982e2e304..4dd5d7969b7 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -1,12 +1,16 @@ package web_test import ( + "errors" "math/big" "net/http" "net/url" "testing" - "github.com/pkg/errors" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/assets" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" @@ -15,17 +19,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" webpresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/google/uuid" + "github.com/smartcontractkit/chainlink/v2/evm/client/clienttest" ) func TestETHKeysController_Index_Success(t *testing.T) { @@ -217,7 +215,7 @@ func TestETHKeysController_CreateSuccess(t *testing.T) { config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) app := cltest.NewApplicationWithConfigAndKey(t, config, ethClient) sub := commonmocks.NewSubscription(t) diff --git a/deployment/environment/memory/node.go b/deployment/environment/memory/node.go index 97e60c646b9..0100c26f6dc 100644 --- a/deployment/environment/memory/node.go +++ b/deployment/environment/memory/node.go @@ -169,7 +169,7 @@ func NewNode( mailMon := mailbox.NewMonitor("node", lggr.Named("mailbox")) evmOpts := chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, + ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), ListenerConfig: cfg.Database().Listener(), FeatureConfig: cfg.Feature(), diff --git a/evm/config/chain_scoped.go b/evm/config/chain_scoped.go index eb29a49d012..37d8faa43f4 100644 --- a/evm/config/chain_scoped.go +++ b/evm/config/chain_scoped.go @@ -5,22 +5,16 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink/v2/evm/config/chaintype" "github.com/smartcontractkit/chainlink/v2/evm/config/toml" ) -func NewTOMLChainScopedConfig(tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { - return &ChainScoped{ - evmConfig: &EVMConfig{C: tomlConfig}, - lggr: lggr} +func NewTOMLChainScopedConfig(tomlConfig *toml.EVMConfig) *ChainScoped { + return &ChainScoped{evmConfig: &EVMConfig{C: tomlConfig}} } -// ChainScoped implements config.ChainScopedConfig with a gencfg.BasicConfig and EVMConfig. +// ChainScoped implements config.ChainScopedConfig with EVMConfig. type ChainScoped struct { - lggr logger.Logger - evmConfig *EVMConfig } diff --git a/evm/config/configtest/configtest.go b/evm/config/configtest/configtest.go index facefec5548..9092b81c001 100644 --- a/evm/config/configtest/configtest.go +++ b/evm/config/configtest/configtest.go @@ -3,13 +3,12 @@ package configtest import ( "testing" - "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/evm/config" "github.com/smartcontractkit/chainlink/v2/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/evm/utils/big" ) -func NewChainScopedConfig(t testing.TB, overrideFn func(c *toml.EVMConfig)) config.ChainScopedConfig { +func NewChainScopedConfig(t testing.TB, overrideFn func(c *toml.EVMConfig)) *config.ChainScoped { chainID := big.NewI(0) evmCfg := &toml.EVMConfig{ ChainID: chainID, @@ -24,5 +23,5 @@ func NewChainScopedConfig(t testing.TB, overrideFn func(c *toml.EVMConfig)) conf overrideFn(evmCfg) } - return config.NewTOMLChainScopedConfig(evmCfg, logger.Test(t)) + return config.NewTOMLChainScopedConfig(evmCfg) } diff --git a/evm/config/toml/config.go b/evm/config/toml/config.go index 64fe11372d6..ff41176c853 100644 --- a/evm/config/toml/config.go +++ b/evm/config/toml/config.go @@ -163,6 +163,17 @@ func (cs EVMConfigs) NodeStatus(name string) (commontypes.NodeStatus, error) { return commontypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, ErrNotFound) } +func (cs EVMConfigs) RPCEnabled() bool { + for _, c := range cs { + if c.IsEnabled() { + if len(c.Nodes) > 0 { + return true + } + } + } + return false +} + func legacyNode(n *Node, chainID *big.Big) (v2 types.Node) { v2.Name = *n.Name v2.EVMChainID = *chainID diff --git a/evm/gas/fee_history_estimator_test.go b/evm/gas/fee_history_estimator_test.go index 8371db8fac1..ae3bb6452f0 100644 --- a/evm/gas/fee_history_estimator_test.go +++ b/evm/gas/fee_history_estimator_test.go @@ -65,7 +65,7 @@ func TestFeeHistoryEstimatorLifecycle(t *testing.T) { CacheTimeout: 10 * time.Second, } - u := gas.NewFeeHistoryEstimator(logger.Test(t), nil, cfg, chainID, nil) + u := gas.NewFeeHistoryEstimator(logger.Test(t), client, cfg, chainID, nil) err := u.Start(tests.Context(t)) assert.NoError(t, err) err = u.Close() diff --git a/evm/testutils/config.go b/evm/testutils/config.go index e95541bd276..e1b85905606 100644 --- a/evm/testutils/config.go +++ b/evm/testutils/config.go @@ -3,8 +3,6 @@ package testutils import ( "testing" - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink/v2/evm/config" "github.com/smartcontractkit/chainlink/v2/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/evm/utils/big" @@ -26,5 +24,5 @@ func NewTestChainScopedConfig(t testing.TB, overrideFn func(c *toml.EVMConfig)) overrideFn(evmCfg) } - return config.NewTOMLChainScopedConfig(evmCfg, logger.Test(t)) + return config.NewTOMLChainScopedConfig(evmCfg) } From 26cd2922101ef5f46befe38d1be0d8274300cb31 Mon Sep 17 00:00:00 2001 From: Makram Date: Mon, 3 Feb 2025 16:22:56 +0200 Subject: [PATCH 36/43] integration-tests/smoke/ccip: fix fSign reading (#16191) * integration-tests/smoke/ccip: fix fSign reading Add TestCCIPReader_GetRMNRemoteConfig to test that fSign reading is correctly done in the CCIP reader. There was no coverage for this before. * bump to main --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- deployment/go.mod | 2 +- deployment/go.sum | 4 +- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 +- .../smoke/ccip/ccip_reader_test.go | 116 ++++++++++++++++++ 11 files changed, 131 insertions(+), 15 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 3ce567869e7..decd988fff7 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -315,7 +315,7 @@ require ( github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect github.com/smartcontractkit/chain-selectors v1.0.37 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 9a0feaf87f6..014d0110a54 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1329,8 +1329,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 h1:+/KEPuWctPObgOoEEBCnli1/H3XnjMdCY3Tn+J32XRM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= diff --git a/deployment/go.mod b/deployment/go.mod index 3e06dcd4dd7..343e85ea989 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -31,7 +31,7 @@ require ( github.com/sethvargo/go-retry v0.2.4 github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix github.com/smartcontractkit/chain-selectors v1.0.37 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b diff --git a/deployment/go.sum b/deployment/go.sum index e0575ed2b07..98a517e366d 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1394,8 +1394,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 h1:+/KEPuWctPObgOoEEBCnli1/H3XnjMdCY3Tn+J32XRM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= diff --git a/go.mod b/go.mod index 9af68f0aa4c..0e2c8dba5a8 100644 --- a/go.mod +++ b/go.mod @@ -78,7 +78,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 diff --git a/go.sum b/go.sum index 47aa94e08d5..49c7690cf38 100644 --- a/go.sum +++ b/go.sum @@ -1154,8 +1154,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 h1:+/KEPuWctPObgOoEEBCnli1/H3XnjMdCY3Tn+J32XRM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36/go.mod h1:Z2e1ynSJ4pg83b4Qldbmryc5lmnrI3ojOdg1FUloa68= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc h1:WZERXv2hTYRA0NpWg79ci/ZZSxucmvkty39iUOV8d7I= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index cc1cb7fc05a..45cb3468668 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -48,7 +48,7 @@ require ( github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.37 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-testing-framework/framework v0.4.7 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 276597c23ff..f9426cd0a10 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1422,8 +1422,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 h1:+/KEPuWctPObgOoEEBCnli1/H3XnjMdCY3Tn+J32XRM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 1bf6c72d5c9..1900e010cb1 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -28,7 +28,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.37 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.21 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.10 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 221bad9fbbd..a35db649f9f 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1409,8 +1409,8 @@ github.com/smartcontractkit/chain-selectors v1.0.37 h1:EKVl8wayhOVfnlqfVmEyZ8rXO github.com/smartcontractkit/chain-selectors v1.0.37/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-20250130101703-5ba045c38d49 h1:Y9mC8DCJQUjU7IwGi0FVsH2Q8ujv9Na8DLq1StsGbso= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20250130101703-5ba045c38d49/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9 h1:+/KEPuWctPObgOoEEBCnli1/H3XnjMdCY3Tn+J32XRM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20250203130001-13e2609047e9/go.mod h1:UEnHaxkUsfreeA7rR45LMmua1Uen95tOFUR8/AI9BAo= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 h1:R1fQXQL1AKLfRqZHlbGO0NHN3uZKEkI3r2uBlctwt7k= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60= github.com/smartcontractkit/chainlink-common v0.4.2-0.20250130202959-6f1f48342e36 h1:bS51NFGHVjkCy7yu9L2Ss4sBsCW6jpa5GuhRAdWWxzM= diff --git a/integration-tests/smoke/ccip/ccip_reader_test.go b/integration-tests/smoke/ccip/ccip_reader_test.go index b260d6dfc81..cf4495d902b 100644 --- a/integration-tests/smoke/ccip/ccip_reader_test.go +++ b/integration-tests/smoke/ccip/ccip_reader_test.go @@ -42,6 +42,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_proxy_contract" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_remote" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" @@ -180,6 +182,120 @@ func emitCommitReports(ctx context.Context, t *testing.T, s *testSetupData, numR return firstReportTs } +func TestCCIPReader_GetRMNRemoteConfig(t *testing.T) { + t.Parallel() + ctx := tests.Context(t) + sb, auth := setupSimulatedBackendAndAuth(t) + + rmnRemoteAddr, _, _, err := rmn_remote.DeployRMNRemote(auth, sb.Client(), uint64(chainD), utils.RandomAddress()) + require.NoError(t, err) + sb.Commit() + + proxyAddr, _, _, err := rmn_proxy_contract.DeployRMNProxy(auth, sb.Client(), rmnRemoteAddr) + require.NoError(t, err) + sb.Commit() + + t.Logf("Proxy address: %s, rmn remote address: %s", proxyAddr.Hex(), rmnRemoteAddr.Hex()) + + proxy, err := rmn_proxy_contract.NewRMNProxy(proxyAddr, sb.Client()) + require.NoError(t, err) + + currARM, err := proxy.GetARM(&bind.CallOpts{ + Context: ctx, + }) + require.NoError(t, err) + require.Equal(t, currARM, rmnRemoteAddr) + + rmnRemote, err := rmn_remote.NewRMNRemote(rmnRemoteAddr, sb.Client()) + require.NoError(t, err) + + _, err = rmnRemote.SetConfig(auth, rmn_remote.RMNRemoteConfig{ + RmnHomeContractConfigDigest: utils.RandomBytes32(), + Signers: []rmn_remote.RMNRemoteSigner{ + { + OnchainPublicKey: utils.RandomAddress(), + NodeIndex: 0, + }, + { + OnchainPublicKey: utils.RandomAddress(), + NodeIndex: 1, + }, + { + OnchainPublicKey: utils.RandomAddress(), + NodeIndex: 2, + }, + }, + FSign: 1, // 2*FSign + 1 == 3 + }) + require.NoError(t, err) + sb.Commit() + + db := pgtest.NewSqlxDB(t) + lggr := logger.TestLogger(t) + lggr.SetLogLevel(zapcore.ErrorLevel) + lpOpts := logpoller.Opts{ + PollPeriod: time.Millisecond, + FinalityDepth: 1, + BackfillBatchSize: 10, + RpcBatchSize: 10, + KeepFinalizedBlocksDepth: 100000, + } + cl := client.NewSimulatedBackendClient(t, sb, big.NewInt(1337)) + headTracker := headtracker.NewSimulatedHeadTracker(cl, lpOpts.UseFinalityTag, lpOpts.FinalityDepth) + orm := logpoller.NewORM(big.NewInt(1337), db, lggr) + lp := logpoller.NewLogPoller( + orm, + cl, + lggr, + headTracker, + lpOpts, + ) + require.NoError(t, lp.Start(ctx)) + t.Cleanup(func() { require.NoError(t, lp.Close()) }) + + cr, err := evm.NewChainReaderService(ctx, lggr, lp, headTracker, cl, evmconfig.DestReaderConfig) + require.NoError(t, err) + err = cr.Start(ctx) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, cr.Close()) }) + + extendedCr := contractreader.NewExtendedContractReader(cr) + err = extendedCr.Bind(ctx, []types.BoundContract{ + { + Address: proxyAddr.String(), + Name: consts.ContractNameRMNRemote, + }, + }) + require.NoError(t, err) + + reader := ccipreaderpkg.NewCCIPReaderWithExtendedContractReaders( + ctx, + lggr, + map[cciptypes.ChainSelector]contractreader.Extended{ + chainD: extendedCr, + }, + nil, + chainD, + rmnRemoteAddr.Bytes(), + ccipcommon.NewExtraDataCodec(), + ) + + exp, err := rmnRemote.GetVersionedConfig(&bind.CallOpts{ + Context: ctx, + }) + require.NoError(t, err) + + rmnRemoteConfig, err := reader.GetRMNRemoteConfig(ctx) + require.NoError(t, err) + require.Equal(t, exp.Config.RmnHomeContractConfigDigest[:], rmnRemoteConfig.ConfigDigest[:]) + require.Equal(t, len(exp.Config.Signers), len(rmnRemoteConfig.Signers)) + for i, signer := range exp.Config.Signers { + require.Equal(t, signer.OnchainPublicKey.Bytes(), []byte(rmnRemoteConfig.Signers[i].OnchainPublicKey)) + require.Equal(t, signer.NodeIndex, rmnRemoteConfig.Signers[i].NodeIndex) + } + require.Equal(t, exp.Config.FSign, rmnRemoteConfig.FSign) +} + func TestCCIPReader_GetOffRampConfigDigest(t *testing.T) { t.Parallel() ctx := tests.Context(t) From d9e1c15e325891cd53c9a9c8ce228977eea13920 Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:06:24 -0500 Subject: [PATCH 37/43] Update GoReleaser config to avoid adding duplicate images in manifests (#16155) * Update GoReleaser config to avoid adding duplicate images in manifests * Add empty commit * Add empty commit 2 --- .goreleaser.develop.yaml | 580 +++++++++++++++++---------------- .goreleaser.devspace.yaml | 176 +++++----- .goreleaser.production.yaml | 622 ++++++++++++++++++------------------ 3 files changed, 681 insertions(+), 697 deletions(-) diff --git a/.goreleaser.develop.yaml b/.goreleaser.develop.yaml index c633e22fe62..765dab58fc7 100644 --- a/.goreleaser.develop.yaml +++ b/.goreleaser.develop.yaml @@ -1,308 +1,300 @@ version: 2 project_name: chainlink env: - - IMG_PRE={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}localhost:5001{{ end }} - - IMG_TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}develop{{ end }} - - CGO_ENABLED=1 - - VERSION={{ if index .Env "CHAINLINK_VERSION" }}{{ .Env.CHAINLINK_VERSION }}{{ else }}v0.0.0-local{{ end }} + - IMG_PRE={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}localhost:5001{{ end }} + - IMG_TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}develop{{ end }} + - CGO_ENABLED=1 + - VERSION={{ if index .Env "CHAINLINK_VERSION" }}{{ .Env.CHAINLINK_VERSION }}{{ else }}v0.0.0-local{{ end }} release: - disable: "true" + disable: "true" builds: - - targets: - - go_first_class - binary: chainlink - hooks: - post: - - cmd: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} - no_unique_dist_dir: "true" - ldflags: - - -s -w -r=$ORIGIN/libs - - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} - - |- - -extldflags "-Wl,--dynamic-linker={{ if contains .Runtime.Goarch "amd64" -}} - /lib64/ld-linux-x86-64.so.2 - {{- else if contains .Runtime.Goarch "arm64" -}} - /lib/ld-linux-aarch64.so.1 - {{- end }}" - - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Env.VERSION }} - flags: - - -trimpath - - -buildmode=pie + - targets: + - go_first_class + binary: chainlink + hooks: + post: + - cmd: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} + no_unique_dist_dir: "true" + ldflags: + - -s -w -r=$ORIGIN/libs + - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} + - |- + -extldflags "-Wl,--dynamic-linker={{ if contains .Runtime.Goarch "amd64" -}} + /lib64/ld-linux-x86-64.so.2 + {{- else if contains .Runtime.Goarch "arm64" -}} + /lib/ld-linux-aarch64.so.1 + {{- end }}" + - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Env.VERSION }} + flags: + - -trimpath + - -buildmode=pie archives: - - format: binary + - format: binary snapshot: - version_template: '{{ .Env.VERSION }}-{{ .ShortCommit }}' + version_template: "{{ .Env.VERSION }}-{{ .ShortCommit }}" checksum: - name_template: checksums.txt + name_template: checksums.txt dockers: - - id: linux-amd64-chainlink - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}' - - '{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-amd64' - - '{{ .Env.IMG_PRE }}/chainlink:sha-{{ .ShortCommit }}-amd64' - extra_files: - - tmp/libs - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-amd64-chainlink-plugins - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-plugins' - - '{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-plugins-amd64' - - '{{ .Env.IMG_PRE }}/chainlink:sha-{{ .ShortCommit }}-plugins-amd64' - extra_files: - - tmp/libs - - tmp/plugins - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-arm64-chainlink - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-arm64' - - '{{ .Env.IMG_PRE }}/chainlink:sha-{{ .ShortCommit }}-arm64' - extra_files: - - tmp/libs - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-arm64-chainlink-plugins - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-plugins-arm64' - - '{{ .Env.IMG_PRE }}/chainlink:sha-{{ .ShortCommit }}-plugins-arm64' - extra_files: - - tmp/libs - - tmp/plugins - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-amd64-ccip - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}' - - '{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-amd64' - - '{{ .Env.IMG_PRE }}/ccip:sha-{{ .ShortCommit }}-amd64' - extra_files: - - tmp/libs - - ccip/config - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-amd64-ccip-plugins - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-plugins' - - '{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-plugins-amd64' - - '{{ .Env.IMG_PRE }}/ccip:sha-{{ .ShortCommit }}-plugins-amd64' - extra_files: - - tmp/libs - - tmp/plugins - - ccip/config - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-arm64-ccip - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-arm64' - - '{{ .Env.IMG_PRE }}/ccip:sha-{{ .ShortCommit }}-arm64' - extra_files: - - tmp/libs - - ccip/config - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-arm64-ccip-plugins - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-plugins-arm64' - - '{{ .Env.IMG_PRE }}/ccip:sha-{{ .ShortCommit }}-plugins-arm64' - extra_files: - - tmp/libs - - tmp/plugins - - ccip/config - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx + - id: linux-amd64-chainlink + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-amd64" + - "{{ .Env.IMG_PRE }}/chainlink:sha-{{ .ShortCommit }}-amd64" + extra_files: + - tmp/libs + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-amd64-chainlink-plugins + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-plugins-amd64" + - "{{ .Env.IMG_PRE }}/chainlink:sha-{{ .ShortCommit }}-plugins-amd64" + extra_files: + - tmp/libs + - tmp/plugins + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-arm64-chainlink + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-arm64" + - "{{ .Env.IMG_PRE }}/chainlink:sha-{{ .ShortCommit }}-arm64" + extra_files: + - tmp/libs + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-arm64-chainlink-plugins + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink:{{ .Env.IMG_TAG }}-plugins-arm64" + - "{{ .Env.IMG_PRE }}/chainlink:sha-{{ .ShortCommit }}-plugins-arm64" + extra_files: + - tmp/libs + - tmp/plugins + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-amd64-ccip + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-amd64" + - "{{ .Env.IMG_PRE }}/ccip:sha-{{ .ShortCommit }}-amd64" + extra_files: + - tmp/libs + - ccip/config + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-amd64-ccip-plugins + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-plugins-amd64" + - "{{ .Env.IMG_PRE }}/ccip:sha-{{ .ShortCommit }}-plugins-amd64" + extra_files: + - tmp/libs + - tmp/plugins + - ccip/config + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-arm64-ccip + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-arm64" + - "{{ .Env.IMG_PRE }}/ccip:sha-{{ .ShortCommit }}-arm64" + extra_files: + - tmp/libs + - ccip/config + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-arm64-ccip-plugins + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/ccip:{{ .Env.IMG_TAG }}-plugins-arm64" + - "{{ .Env.IMG_PRE }}/ccip:sha-{{ .ShortCommit }}-plugins-arm64" + extra_files: + - tmp/libs + - tmp/plugins + - ccip/config + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx docker_manifests: - - id: tagged-chainlink - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}' - - '{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-arm64' - - id: sha-chainlink - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-arm64' - - id: tagged-plugins-chainlink - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-plugins' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-plugins' - - '{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-plugins-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-plugins-arm64' - - id: sha-plugins-chainlink - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-plugins' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-plugins-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-plugins-arm64' - - id: tagged-ccip - name_template: '{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}' - - '{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-amd64' - - '{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-arm64' - - id: sha-ccip - name_template: '{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-amd64' - - '{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-arm64' - - id: tagged-plugins-ccip - name_template: '{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-plugins' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-plugins' - - '{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-plugins-amd64' - - '{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-plugins-arm64' - - id: sha-plugins-ccip - name_template: '{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-plugins' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-plugins-amd64' - - '{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-plugins-arm64' + - id: tagged-chainlink + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}" + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-arm64" + - id: sha-chainlink + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}" + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-arm64" + - id: tagged-plugins-chainlink + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-plugins" + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-plugins-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink:{{ .Env.IMG_TAG }}-plugins-arm64" + - id: sha-plugins-chainlink + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-plugins" + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-plugins-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink:sha-{{ .ShortCommit }}-plugins-arm64" + - id: tagged-ccip + name_template: "{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}" + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-arm64" + - id: sha-ccip + name_template: "{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}" + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-arm64" + - id: tagged-plugins-ccip + name_template: "{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-plugins" + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-plugins-amd64" + - "{{ .Env.IMAGE_PREFIX }}/ccip:{{ .Env.IMG_TAG }}-plugins-arm64" + - id: sha-plugins-ccip + name_template: "{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-plugins" + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-plugins-amd64" + - "{{ .Env.IMAGE_PREFIX }}/ccip:sha-{{ .ShortCommit }}-plugins-arm64" changelog: - disable: "true" + disable: "true" before: - hooks: - - cmd: go mod tidy - - cmd: ./tools/bin/goreleaser_utils before_hook + hooks: + - cmd: go mod tidy + - cmd: ./tools/bin/goreleaser_utils before_hook partial: - by: target + by: target nightly: - version_template: '{{ .Env.VERSION }}-{{ .Env.IMG_TAG }}' + version_template: "{{ .Env.VERSION }}-{{ .Env.IMG_TAG }}" diff --git a/.goreleaser.devspace.yaml b/.goreleaser.devspace.yaml index 13027590a2b..562bc0e2e0d 100644 --- a/.goreleaser.devspace.yaml +++ b/.goreleaser.devspace.yaml @@ -1,102 +1,102 @@ version: 2 project_name: chainlink env: - - IMG_PRE={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}localhost:5001{{ end }} - - IMG_TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}develop{{ end }} - - CGO_ENABLED=1 + - IMG_PRE={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}localhost:5001{{ end }} + - IMG_TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}develop{{ end }} + - CGO_ENABLED=1 release: - disable: "true" + disable: "true" builds: - - targets: - - go_first_class - binary: chainlink - hooks: - post: - - cmd: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} - no_unique_dist_dir: "true" - ldflags: - - -s -w -r=$ORIGIN/libs - - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} - - |- - -extldflags "-Wl,--dynamic-linker={{ if contains .Runtime.Goarch "amd64" -}} - /lib64/ld-linux-x86-64.so.2 - {{- else if contains .Runtime.Goarch "arm64" -}} - /lib/ld-linux-aarch64.so.1 - {{- end }}" - - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Version }} - flags: - - -trimpath - - -buildmode=pie + - targets: + - go_first_class + binary: chainlink + hooks: + post: + - cmd: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} + no_unique_dist_dir: "true" + ldflags: + - -s -w -r=$ORIGIN/libs + - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} + - |- + -extldflags "-Wl,--dynamic-linker={{ if contains .Runtime.Goarch "amd64" -}} + /lib64/ld-linux-x86-64.so.2 + {{- else if contains .Runtime.Goarch "arm64" -}} + /lib/ld-linux-aarch64.so.1 + {{- end }}" + - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Version }} + flags: + - -trimpath + - -buildmode=pie archives: - - format: binary + - format: binary snapshot: - version_template: v0.0.0-{{ .Runtime.Goarch }}-{{ .Now.Format "2006-01-02-15-04-05Z" }} + version_template: v0.0.0-{{ .Runtime.Goarch }}-{{ .Now.Format "2006-01-02-15-04-05Z" }} checksum: - name_template: checksums.txt + name_template: checksums.txt dockers: - - id: linux-amd64 - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMAGE }}' - extra_files: - - tmp/libs - - tmp/plugins - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - use: buildx - - id: linux-arm64 - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMAGE }}' - extra_files: - - tmp/libs - - tmp/plugins - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - use: buildx + - id: linux-amd64 + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMAGE }}" + extra_files: + - tmp/libs + - tmp/plugins + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + use: buildx + - id: linux-arm64 + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMAGE }}" + extra_files: + - tmp/libs + - tmp/plugins + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + use: buildx docker_manifests: - - name_template: '{{ .Env.IMAGE }}' - image_templates: - - '{{ .Env.IMAGE }}' + - name_template: "{{ .Env.IMAGE }}" + image_templates: + - "{{ .Env.IMAGE }}" changelog: - disable: "true" + disable: "true" before: - hooks: - - cmd: go mod tidy - - cmd: ./tools/bin/goreleaser_utils before_hook + hooks: + - cmd: go mod tidy + - cmd: ./tools/bin/goreleaser_utils before_hook partial: - by: target + by: target nightly: - version_template: v0.0.0-{{ .Runtime.Goarch }}-{{ .Now.Format "2006-01-02-15-04-05Z" }} + version_template: v0.0.0-{{ .Runtime.Goarch }}-{{ .Now.Format "2006-01-02-15-04-05Z" }} diff --git a/.goreleaser.production.yaml b/.goreleaser.production.yaml index b4e19d1b31c..8bf860e719c 100644 --- a/.goreleaser.production.yaml +++ b/.goreleaser.production.yaml @@ -1,330 +1,322 @@ version: 2 project_name: chainlink env: - - IMG_PRE={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}localhost:5001{{ end }} - - IMG_TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}develop{{ end }} - - CGO_ENABLED=1 - - VERSION={{ if index .Env "CHAINLINK_VERSION" }}{{ .Env.CHAINLINK_VERSION }}{{ else }}v0.0.0-local{{ end }} + - IMG_PRE={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}localhost:5001{{ end }} + - IMG_TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}develop{{ end }} + - CGO_ENABLED=1 + - VERSION={{ if index .Env "CHAINLINK_VERSION" }}{{ .Env.CHAINLINK_VERSION }}{{ else }}v0.0.0-local{{ end }} release: - disable: "true" + disable: "true" builds: - - targets: - - go_first_class - binary: chainlink - hooks: - post: - - cmd: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} - no_unique_dist_dir: "true" - ldflags: - - -s -w -r=$ORIGIN/libs - - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} - - |- - -extldflags "-Wl,--dynamic-linker={{ if contains .Runtime.Goarch "amd64" -}} - /lib64/ld-linux-x86-64.so.2 - {{- else if contains .Runtime.Goarch "arm64" -}} - /lib/ld-linux-aarch64.so.1 - {{- end }}" - - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Env.VERSION }} - flags: - - -trimpath - - -buildmode=pie + - targets: + - go_first_class + binary: chainlink + hooks: + post: + - cmd: ./tools/bin/goreleaser_utils build_post_hook {{ dir .Path }} + no_unique_dist_dir: "true" + ldflags: + - -s -w -r=$ORIGIN/libs + - -X github.com/smartcontractkit/chainlink/v2/core/static.Sha={{ .FullCommit }} + - |- + -extldflags "-Wl,--dynamic-linker={{ if contains .Runtime.Goarch "amd64" -}} + /lib64/ld-linux-x86-64.so.2 + {{- else if contains .Runtime.Goarch "arm64" -}} + /lib/ld-linux-aarch64.so.1 + {{- end }}" + - -X github.com/smartcontractkit/chainlink/v2/core/static.Version={{ .Env.VERSION }} + flags: + - -trimpath + - -buildmode=pie archives: - - format: tar.gz + - format: tar.gz snapshot: - version_template: '{{ .Env.VERSION }}-{{ .ShortCommit }}' + version_template: "{{ .Env.VERSION }}-{{ .ShortCommit }}" checksum: - name_template: checksums.txt + name_template: checksums.txt dockers: - - id: linux-amd64-chainlink - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-amd64' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-amd64' - skip_push: '{{ contains .Tag "-ccip" }}' - extra_files: - - tmp/libs - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-amd64-chainlink-plugins - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-amd64' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-amd64' - skip_push: '{{ contains .Tag "-ccip" }}' - extra_files: - - tmp/libs - - tmp/plugins - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-arm64-chainlink - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-arm64' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-arm64' - skip_push: '{{ contains .Tag "-ccip" }}' - extra_files: - - tmp/libs - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-arm64-chainlink-plugins - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-arm64' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-arm64' - skip_push: '{{ contains .Tag "-ccip" }}' - extra_files: - - tmp/libs - - tmp/plugins - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-amd64-ccip - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-amd64' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-amd64' - skip_push: '{{ not (contains .Tag "-ccip") }}' - extra_files: - - tmp/libs - - ccip/config - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-amd64-ccip-plugins - goos: linux - goarch: amd64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-amd64' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-amd64' - skip_push: '{{ not (contains .Tag "-ccip") }}' - extra_files: - - tmp/libs - - tmp/plugins - - ccip/config - build_flag_templates: - - --platform=linux/amd64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-arm64-ccip - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-arm64' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-arm64' - skip_push: '{{ not (contains .Tag "-ccip") }}' - extra_files: - - tmp/libs - - ccip/config - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx - - id: linux-arm64-ccip-plugins - goos: linux - goarch: arm64 - dockerfile: core/chainlink.goreleaser.Dockerfile - image_templates: - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-arm64' - - '{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-arm64' - skip_push: '{{ not (contains .Tag "-ccip") }}' - extra_files: - - tmp/libs - - tmp/plugins - - ccip/config - build_flag_templates: - - --platform=linux/arm64 - - --pull - - --build-arg=CHAINLINK_USER=chainlink - - --build-arg=COMMIT_SHA={{ .FullCommit }} - - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config - - --build-arg=CL_MEDIAN_CMD=chainlink-feeds - - --build-arg=CL_MERCURY_CMD=chainlink-mercury - - --build-arg=CL_SOLANA_CMD=chainlink-solana - - --build-arg=CL_STARKNET_CMD=chainlink-starknet - - --label=org.opencontainers.image.created={{ .Date }} - - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" - - --label=org.opencontainers.image.licenses=MIT - - --label=org.opencontainers.image.revision={{ .FullCommit }} - - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.title=chainlink - - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink - - --label=org.opencontainers.image.version={{ .Env.VERSION }} - use: buildx + - id: linux-amd64-chainlink + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-amd64" + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-amd64" + skip_push: '{{ contains .Tag "-ccip" }}' + extra_files: + - tmp/libs + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-amd64-chainlink-plugins + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-amd64" + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-amd64" + skip_push: '{{ contains .Tag "-ccip" }}' + extra_files: + - tmp/libs + - tmp/plugins + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-arm64-chainlink + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-arm64" + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-arm64" + skip_push: '{{ contains .Tag "-ccip" }}' + extra_files: + - tmp/libs + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-arm64-chainlink-plugins + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-arm64" + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-arm64" + skip_push: '{{ contains .Tag "-ccip" }}' + extra_files: + - tmp/libs + - tmp/plugins + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-amd64-ccip + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-amd64" + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-amd64" + skip_push: '{{ not (contains .Tag "-ccip") }}' + extra_files: + - tmp/libs + - ccip/config + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-amd64-ccip-plugins + goos: linux + goarch: amd64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-amd64" + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-amd64" + skip_push: '{{ not (contains .Tag "-ccip") }}' + extra_files: + - tmp/libs + - tmp/plugins + - ccip/config + build_flag_templates: + - --platform=linux/amd64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-arm64-ccip + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-arm64" + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-arm64" + skip_push: '{{ not (contains .Tag "-ccip") }}' + extra_files: + - tmp/libs + - ccip/config + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx + - id: linux-arm64-ccip-plugins + goos: linux + goarch: arm64 + dockerfile: core/chainlink.goreleaser.Dockerfile + image_templates: + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-arm64" + - "{{ .Env.IMG_PRE }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-arm64" + skip_push: '{{ not (contains .Tag "-ccip") }}' + extra_files: + - tmp/libs + - tmp/plugins + - ccip/config + build_flag_templates: + - --platform=linux/arm64 + - --pull + - --build-arg=CHAINLINK_USER=chainlink + - --build-arg=COMMIT_SHA={{ .FullCommit }} + - --build-arg=CL_CHAIN_DEFAULTS=/chainlink/ccip-config + - --build-arg=CL_MEDIAN_CMD=chainlink-feeds + - --build-arg=CL_MERCURY_CMD=chainlink-mercury + - --build-arg=CL_SOLANA_CMD=chainlink-solana + - --build-arg=CL_STARKNET_CMD=chainlink-starknet + - --label=org.opencontainers.image.created={{ .Date }} + - --label=org.opencontainers.image.description="node of the decentralized oracle network, bridging on and off-chain computation" + - --label=org.opencontainers.image.licenses=MIT + - --label=org.opencontainers.image.revision={{ .FullCommit }} + - --label=org.opencontainers.image.source=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.title=chainlink + - --label=org.opencontainers.image.url=https://github.com/smartcontractkit/chainlink + - --label=org.opencontainers.image.version={{ .Env.VERSION }} + use: buildx docker_manifests: - - id: tagged-chainlink-chainlink-experimental-goreleaser - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}' - skip_push: '{{ contains .Tag "-ccip" }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-arm64' - - id: sha-chainlink-chainlink-experimental-goreleaser - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}' - skip_push: '{{ contains .Tag "-ccip" }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-arm64' - - id: tagged-plugins-chainlink-chainlink-experimental-goreleaser - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins' - skip_push: '{{ contains .Tag "-ccip" }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-arm64' - - id: sha-plugins-chainlink-chainlink-experimental-goreleaser - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins' - skip_push: '{{ contains .Tag "-ccip" }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-arm64' - - id: tagged-chainlink-chainlink-ccip-experimental-goreleaser - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}' - skip_push: '{{ not (contains .Tag "-ccip") }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-arm64' - - id: sha-chainlink-chainlink-ccip-experimental-goreleaser - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}' - skip_push: '{{ not (contains .Tag "-ccip") }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-arm64' - - id: tagged-plugins-chainlink-chainlink-ccip-experimental-goreleaser - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins' - skip_push: '{{ not (contains .Tag "-ccip") }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-arm64' - - id: sha-plugins-chainlink-chainlink-ccip-experimental-goreleaser - name_template: '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins' - skip_push: '{{ not (contains .Tag "-ccip") }}' - image_templates: - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-amd64' - - '{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-arm64' + - id: tagged-chainlink-chainlink-experimental-goreleaser + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}" + skip_push: '{{ contains .Tag "-ccip" }}' + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-arm64" + - id: sha-chainlink-chainlink-experimental-goreleaser + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}" + skip_push: '{{ contains .Tag "-ccip" }}' + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-arm64" + - id: tagged-plugins-chainlink-chainlink-experimental-goreleaser + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins" + skip_push: '{{ contains .Tag "-ccip" }}' + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-arm64" + - id: sha-plugins-chainlink-chainlink-experimental-goreleaser + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins" + skip_push: '{{ contains .Tag "-ccip" }}' + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-arm64" + - id: tagged-chainlink-chainlink-ccip-experimental-goreleaser + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}" + skip_push: '{{ not (contains .Tag "-ccip") }}' + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-arm64" + - id: sha-chainlink-chainlink-ccip-experimental-goreleaser + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}" + skip_push: '{{ not (contains .Tag "-ccip") }}' + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-arm64" + - id: tagged-plugins-chainlink-chainlink-ccip-experimental-goreleaser + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins" + skip_push: '{{ not (contains .Tag "-ccip") }}' + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:{{ .Env.IMG_TAG }}-plugins-arm64" + - id: sha-plugins-chainlink-chainlink-ccip-experimental-goreleaser + name_template: "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins" + skip_push: '{{ not (contains .Tag "-ccip") }}' + image_templates: + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-amd64" + - "{{ .Env.IMAGE_PREFIX }}/chainlink/chainlink-ccip-experimental-goreleaser:sha-{{ .ShortCommit }}-plugins-arm64" changelog: - filters: - exclude: - - '^docs:' - - '^test:' - sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + sort: asc before: - hooks: - - cmd: go mod tidy - - cmd: ./tools/bin/goreleaser_utils before_hook + hooks: + - cmd: go mod tidy + - cmd: ./tools/bin/goreleaser_utils before_hook sboms: - - artifacts: archive + - artifacts: archive partial: - by: target + by: target nightly: - version_template: '{{ .Env.VERSION }}-{{ .Env.IMG_TAG }}' + version_template: "{{ .Env.VERSION }}-{{ .Env.IMG_TAG }}" From 4052d7adf3645d8f70cea56007c26e1b565e3ede Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Mon, 3 Feb 2025 16:30:58 +0100 Subject: [PATCH 38/43] [TT-1981] use chainlink cli in the keystone smoke test (#16146) * WIP, almost working... last step fails, when forwarder calls DF cache * working version * use newer PoR workflow * now its broken again * Update gethwrappers * go back to previous config, where all steps were correcty configured * use older config * fix port * use debug consumer contract * WORKING VERSION * remove mock streams capability * passes with workflow registry deployed with c/d * passes with keystone consumer deployed with c/d * passes with keystone forwarder deployed with c/d * remove some deps * allow to use chainlink-cli * restore old KeystoneFeedsConsumer.sol contract * try to run the test in CI * fix integration workflow * move the function * use existing env vars to get the image, use e2e tests workflow version that sets GH_TOKEN as env var available to tests * add missing PRIVATE_KEY env var * pass optional roles for GATI to be able to read from repositories * add some comments, update e2e workflow commit * add comments * fix integration tests workflow file * newer workflow version * update token name and workflow version * do not use chainlink CLI in the CI for now (we need a token that can access it) * fix env var name in CI * fix capability reference * clean up the workflow test * move capability test to smoke subfolder * restore old versions of feeds consumer wrapper * rename GITHUB_TOKEN env var to GITHUB_API_TOKEN * try one more approach to resolving placeholder env var * adjust env file to new location * revert testing-related changes to integration tests workflow * fix lints * use function from chainlink-common to generate workflow id, define new constants for binary file names * add JD * use C/D to setup all contracts * add extra debug information * fix lint * poll config every 500ms * change polling interval to 1s * fix config polling intervnal * use only chainlink/deployments when interacting with contract * JD is failing to create jobs due to a bug and authorization issue * do not use JD to setup jobs * CR changes * adjust to latest changes, move some configs to TOML * CR changes * move comments around * add test modification guideline and better debugging * fix config validations * fix lints * use fixed JD version in the CI * remove workflow registration artifact file * restore older environment file * get p2p ide from node labels, more comments, use contractset * fix lints and remove superfluous methods * dynamic transmission schedule * try out chainlink-cli in the CI * use configurable workflow_id also when registering the workflow * support configurable capabilities/chainlink-cli versions * remove unused struct * fix TOML * make chainlink-cli os/arch aware and extract it to the current folder * run chainlink-cli from current directory * use absolute path when running chainlink-cli * fix if condition * add ocr3 config accidentally deleted when resolving merge conflicts * add info about JD image to guidelines * code review changes + renaming of chainlink-cli to CRE CLI + configuration simplification --------- Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> --- .../smoke/capabilities/.gitignore | 8 +- .../smoke/capabilities/environment-ci.toml | 10 +- .../smoke/capabilities/environment.toml | 14 +- .../smoke/capabilities/guidelines.md | 33 ++- .../smoke/capabilities/workflow_test.go | 275 ++++++++++-------- 5 files changed, 194 insertions(+), 146 deletions(-) diff --git a/integration-tests/smoke/capabilities/.gitignore b/integration-tests/smoke/capabilities/.gitignore index 03d90d23455..a532a0fe18f 100644 --- a/integration-tests/smoke/capabilities/.gitignore +++ b/integration-tests/smoke/capabilities/.gitignore @@ -1,6 +1,8 @@ # CTFv2 cached environment, no point in committing this *-cache.toml -# compiled cron capability +# compiled cron capability, it should be downloaded by the test amd64_cron -# workflow registration artifact -abcdefgasd.yaml \ No newline at end of file +# workflow registration artifact, it's created anew every time the workflow is registered +abcdefgasd.yaml +# chainlink cli binary, it should be downloaded by the test +cre_v* \ No newline at end of file diff --git a/integration-tests/smoke/capabilities/environment-ci.toml b/integration-tests/smoke/capabilities/environment-ci.toml index 4ba6cbdc1ac..968e1fabd3e 100644 --- a/integration-tests/smoke/capabilities/environment-ci.toml +++ b/integration-tests/smoke/capabilities/environment-ci.toml @@ -12,10 +12,14 @@ # without 0x prefix! feed_id = "018bfe8840700040000000000000000000000000000000000000000000000000" - use_chainlink_cli = false - use_existing = true + use_cre_cli = true + should_compile_new_workflow = false - [workflow_config.existing] + [workflow_config.dependencies] + capabilities_version = "v1.0.0-alpha" + cre_cli_version = "v1.0.2" + + [workflow_config.compiled_config] binary_url = "https://gist.githubusercontent.com/Tofel/8a39af5b68c213d2200446c175b5c99e/raw/cb7b2a56b37e333fe0bdce07b79538c4ce332f5f/binary.wasm.br" config_url = "https://gist.githubusercontent.com/Tofel/19c80e6297914a79449f916e5e65dfdd/raw/1344c259ef7e970dbabaa1e9e885845b8eba5da9/config.json3674692696" diff --git a/integration-tests/smoke/capabilities/environment.toml b/integration-tests/smoke/capabilities/environment.toml index b6db7e5676d..b6f648c7136 100644 --- a/integration-tests/smoke/capabilities/environment.toml +++ b/integration-tests/smoke/capabilities/environment.toml @@ -13,16 +13,18 @@ # without 0x prefix! feed_id = "018bfe8840700040000000000000000000000000000000000000000000000000" - use_chainlink_cli = true - use_existing = true + use_cre_cli = true + should_compile_new_workflow = true + workflow_folder_location = "path-to-folder-with-main.go-of-your-workflow" - [workflow_config.existing] + [workflow_config.dependencies] + capabilities_version = "v1.0.0-alpha" + cre_cli_version = "v1.0.2" + + [workflow_config.compiled_config] binary_url = "https://gist.githubusercontent.com/Tofel/8a39af5b68c213d2200446c175b5c99e/raw/cb7b2a56b37e333fe0bdce07b79538c4ce332f5f/binary.wasm.br" config_url = "https://gist.githubusercontent.com/Tofel/19c80e6297914a79449f916e5e65dfdd/raw/1344c259ef7e970dbabaa1e9e885845b8eba5da9/config.json3674692696" - [workflow_config.chainlink_cli] - folder_location = "path-to-folder-with-main.go-of-your-workflow" - [nodeset] nodes = 5 override_mode = "each" diff --git a/integration-tests/smoke/capabilities/guidelines.md b/integration-tests/smoke/capabilities/guidelines.md index 4195bea12cb..fe1b992309d 100644 --- a/integration-tests/smoke/capabilities/guidelines.md +++ b/integration-tests/smoke/capabilities/guidelines.md @@ -41,9 +41,16 @@ The test requires several environment variables. Below is a launch configuration } ``` -- **`GITHUB_READ_TOKEN`**: Required for downloading the `cron` capability binary and `chainlink-cli` (if enabled). Requires `content:read` permission for `smartcontractkit/capabilities` and `smartcontractkit/dev-platform` repositories. Use a fine-grained personal access token (PAT) tied to the **organization’s GitHub account**. +- **`GITHUB_READ_TOKEN`**: Required for downloading the `cron` capability binary and CRE CLI (if enabled). Requires `content:read` permission for `smartcontractkit/capabilities` and `smartcontractkit/dev-platform` repositories. Use a fine-grained personal access token (PAT) tied to the **organization’s GitHub account**. - **`GIST_WRITE_TOKEN`**: Required only for compiling and uploading a new workflow. It needs `gist:read:write` permissions and should be a fine-grained PAT **tied to your personal GitHub account**. +Test also expects you to have the Job Distributor image available locally. By default, `environment.toml` expects image tagged as `jd-test-1:latest`. The easiest way to get it, is to clone the Job Distributor repository and build it locally with: +```bash +docker build -t jd-test-1 -f e2e/Dockerfile.e2e +``` + +Alternatively, if you have access to the Docker image repository where it's stored you can modify `environment.toml` with the name of the image stored there. + --- ## Adding a New Capability @@ -123,16 +130,14 @@ For the test to compile and upload the binary, modify your TOML configuration: ```toml [workflow_config] - use_chainlink_cli = true - use_existing = false - - [workflow_config.chainlink_cli] - folder_location = "path-to-folder-with-main.go-of-your-workflow" + use_cre_cli = true + should_compile_new_workflow = true + workflow_folder_location = "path-to-folder-with-main.go-of-your-workflow" ``` ### Workflow Configuration -If your workflow requires configuration, modify the test to create and pass the configuration data to `chainlink-cli`: +If your workflow requires configuration, modify the test to create and pass the configuration data to CRE CLI: ```go configFile, err := os.CreateTemp("", "config.json") @@ -156,10 +161,10 @@ If you compiled and uploaded the binary yourself, set the following in your conf ```toml [workflow_config] - use_chainlink_cli = true - use_existing = true + use_cre_cli = true + should_compile_new_workflow = false - [workflow_config.existing] + [workflow_config.compiled_config] binary_url = "" config_url = "" ``` @@ -176,11 +181,9 @@ If the deployer private key or deployment sequence changes, run the test in **up ```toml [workflow_config] - use_chainlink_cli = true - use_existing = false - - [workflow_config.chainlink_cli] - folder_location = "path-to-folder-with-main.go-of-your-workflow" + use_cre_cli = true + should_compile_new_workflow = true + workflow_folder_location = "path-to-folder-with-main.go-of-your-workflow" ``` --- diff --git a/integration-tests/smoke/capabilities/workflow_test.go b/integration-tests/smoke/capabilities/workflow_test.go index c9fa136c597..2b984443971 100644 --- a/integration-tests/smoke/capabilities/workflow_test.go +++ b/integration-tests/smoke/capabilities/workflow_test.go @@ -17,6 +17,7 @@ import ( "os/exec" "path/filepath" "regexp" + "runtime" "strconv" "strings" "sync" @@ -40,7 +41,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/jd" ns "github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set" - "github.com/smartcontractkit/chainlink-testing-framework/lib/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/seth" "github.com/smartcontractkit/chainlink/deployment" @@ -61,10 +61,12 @@ import ( ) type WorkflowConfig struct { - UseChainlinkCLI bool `toml:"use_chainlink_cli"` - ChainlinkCLI *ChainlinkCLIConfig `toml:"chainlink_cli"` - UseExising bool `toml:"use_existing"` - Existing *ExistingWorkflowConfig `toml:"existing"` + UseCRECLI bool `toml:"use_cre_cli"` + ShouldCompileNewWorkflow bool `toml:"should_compile_new_workflow"` + // Tells the test where the workflow to compile is located + WorkflowFolderLocation *string `toml:"workflow_folder_location"` + CompiledWorkflowConfig *CompiledConfig `toml:"compiled_config"` + DependenciesConfig *DependenciesConfig `toml:"dependencies"` // id, which will be used, when registering the DON with the workflow registry, // and when instructing the Gateway job on the bootstrap node as to which workflow to run. DonID uint32 `toml:"don_id" validate:"required"` @@ -72,13 +74,18 @@ type WorkflowConfig struct { FeedID string `toml:"feed_id" validate:"required"` } -type ExistingWorkflowConfig struct { - BinaryURL string `toml:"binary_url"` - ConfigURL string `toml:"config_url"` +// Defines relases/versions of test dependencies that will be downloaded from Github +type DependenciesConfig struct { + CapabiltiesVersion string `toml:"capabilities_version"` + CRECLIVersion string `toml:"cre_cli_version"` } -type ChainlinkCLIConfig struct { - FolderLocation *string `toml:"folder_location"` +// Defines the location of already compiled workflow binary and config files +// They will be used if WorkflowConfig.ShouldCompileNewWorkflow is `false` +// Otherwise test will compile and upload a new workflow +type CompiledConfig struct { + BinaryURL string `toml:"binary_url"` + ConfigURL string `toml:"config_url"` } type WorkflowTestConfig struct { @@ -88,72 +95,67 @@ type WorkflowTestConfig struct { JD *jd.Input `toml:"jd" validate:"required"` } -func downloadGHAssetFromLatestRelease(owner, repository, releaseType, assetName, ghToken string) ([]byte, error) { +func downloadGHAssetFromRelease(owner, repository, releaseTag, assetName, ghToken string) ([]byte, error) { var content []byte if ghToken == "" { return content, errors.New("no github token provided") } - if (releaseType == test_env.AUTOMATIC_LATEST_TAG) || (releaseType == test_env.AUTOMATIC_STABLE_LATEST_TAG) { - ctx := context.Background() - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: ghToken}, - ) - tc := oauth2.NewClient(ctx, ts) + // assuming 180s is enough to fetch releases, find the asset we need and download it + // some assets might be 30+ MB, so we need to give it some time (for really slow connections) + ctx, cancelFn := context.WithTimeout(context.Background(), 180*time.Second) + defer cancelFn() + ts := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: ghToken}, + ) + tc := oauth2.NewClient(ctx, ts) - ghClient := github.NewClient(tc) + ghClient := github.NewClient(tc) - latestTags, _, err := ghClient.Repositories.ListReleases(context.Background(), owner, repository, &github.ListOptions{PerPage: 20}) - if err != nil { - return content, errors.Wrapf(err, "failed to list releases for %s", repository) - } + ghReleases, _, err := ghClient.Repositories.ListReleases(ctx, owner, repository, &github.ListOptions{PerPage: 20}) + if err != nil { + return content, errors.Wrapf(err, "failed to list releases for %s", repository) + } - var latestRelease *github.RepositoryRelease - for _, tag := range latestTags { - if releaseType == test_env.AUTOMATIC_STABLE_LATEST_TAG { - if tag.Prerelease != nil && *tag.Prerelease { - continue - } - if tag.Draft != nil && *tag.Draft { - continue - } - } - if tag.TagName != nil { - latestRelease = tag - break - } + var ghRelease *github.RepositoryRelease + for _, release := range ghReleases { + if release.TagName == nil { + continue } - if latestRelease == nil { - return content, errors.New("failed to find latest release with automatic tag: " + releaseType) + if *release.TagName == releaseTag { + ghRelease = release + break } + } - var assetID int64 - for _, asset := range latestRelease.Assets { - if strings.Contains(asset.GetName(), assetName) { - assetID = asset.GetID() - break - } - } + if ghRelease == nil { + return content, errors.New("failed to find release with tag: " + releaseTag) + } - if assetID == 0 { - return content, fmt.Errorf("failed to find asset %s for %s", assetName, *latestRelease.TagName) + var assetID int64 + for _, asset := range ghRelease.Assets { + if strings.Contains(asset.GetName(), assetName) { + assetID = asset.GetID() + break } + } - asset, _, err := ghClient.Repositories.DownloadReleaseAsset(context.Background(), owner, repository, assetID, tc) - if err != nil { - return content, errors.Wrapf(err, "failed to download asset %s for %s", assetName, *latestRelease.TagName) - } + if assetID == 0 { + return content, fmt.Errorf("failed to find asset %s for %s", assetName, *ghRelease.TagName) + } - content, err = io.ReadAll(asset) - if err != nil { - return content, err - } + asset, _, err := ghClient.Repositories.DownloadReleaseAsset(ctx, owner, repository, assetID, tc) + if err != nil { + return content, errors.Wrapf(err, "failed to download asset %s for %s", assetName, *ghRelease.TagName) + } - return content, nil + content, err = io.ReadAll(asset) + if err != nil { + return content, err } - return content, errors.New("no automatic tag provided") + return content, nil } func GenerateWorkflowIDFromStrings(owner string, name string, workflow []byte, config []byte, secretsURL string) (string, error) { @@ -221,7 +223,7 @@ func downloadAndDecode(url string) ([]byte, error) { return decoded, nil } -type ChainlinkCliSettings struct { +type CRECLISettings struct { DevPlatform DevPlatform `yaml:"dev-platform"` UserWorkflow UserWorkflow `yaml:"user-workflow"` Logging Logging `yaml:"logging"` @@ -270,52 +272,83 @@ type PoRWorkflowConfig struct { } const ( - chainlinkCliAssetFile = "cre_v1.0.2_linux_amd64.tar.gz" + CRECLISettingsFileName = ".cre-cli-settings.yaml" cronCapabilityAssetFile = "amd64_cron" e2eJobDistributorImageEnvVarName = "E2E_JD_IMAGE" e2eJobDistributorVersionEnvVarName = "E2E_JD_VERSION" ghReadTokenEnvVarName = "GITHUB_READ_TOKEN" ) -func downloadAndInstallChainlinkCLI(ghToken string) error { - content, err := downloadGHAssetFromLatestRelease("smartcontractkit", "dev-platform", test_env.AUTOMATIC_LATEST_TAG, chainlinkCliAssetFile, ghToken) +var ( + CRECLICommand string +) + +func downloadAndInstallChainlinkCLI(ghToken, version string) error { + system := runtime.GOOS + arch := runtime.GOARCH + + switch system { + case "darwin", "linux": + // nothing to do, we have the binaries + default: + return fmt.Errorf("chainlnk-cli does not support OS: %s", system) + } + + switch arch { + case "amd64", "arm64": + // nothing to do, we have the binaries + default: + return fmt.Errorf("chainlnk-cli does not support arch: %s", arch) + } + + CRECLIAssetFile := fmt.Sprintf("cre_%s_%s_%s.tar.gz", version, system, arch) + content, err := downloadGHAssetFromRelease("smartcontractkit", "dev-platform", version, CRECLIAssetFile, ghToken) if err != nil { - return err + return errors.Wrapf(err, "failed to download CRE CLI asset %s", CRECLIAssetFile) } - tmpfile, err := os.CreateTemp("", chainlinkCliAssetFile) + tmpfile, err := os.CreateTemp("", CRECLIAssetFile) if err != nil { - return err + return errors.Wrapf(err, "failed to create temp file for CRE CLI asset %s", CRECLIAssetFile) } defer tmpfile.Close() if _, err := tmpfile.Write(content); err != nil { - return err + return errors.Wrapf(err, "failed to write content to temp file for CRE CLI asset %s", CRECLIAssetFile) } - cmd := exec.Command("tar", "-xvf", tmpfile.Name()) // #nosec G204 - err = cmd.Run() + cmd := exec.Command("tar", "-xvf", tmpfile.Name(), "-C", ".") // #nosec G204 + if cmd.Run() != nil { + return errors.Wrapf(err, "failed to extract CRE CLI asset %s", CRECLIAssetFile) + } - if err != nil { - return err + extractedFileName := fmt.Sprintf("cre_%s_%s_%s", version, system, arch) + cmd = exec.Command("chmod", "+x", extractedFileName) + if cmd.Run() != nil { + return errors.Wrapf(err, "failed to make %s executable", extractedFileName) } - cmd = exec.Command("chmod", "+x", "chainlink-cli") - err = cmd.Run() + // set it to absolute path, because some commands (e.g. compile) need to be executed in the context + // of the workflow directory + extractedFile, err := os.Open(extractedFileName) + if err != nil { + return errors.Wrapf(err, "failed to open %s", extractedFileName) + } + CRECLICommand, err = filepath.Abs(extractedFile.Name()) if err != nil { - return err + return errors.Wrapf(err, "failed to get absolute path for %s", tmpfile.Name()) } - if isInstalled := isInstalled("chainlink-cli"); !isInstalled { - return errors.New("failed to install chainlink-cli or it is not available in the PATH") + if isInstalled := isInstalled(CRECLICommand); !isInstalled { + return errors.New("failed to install CRE CLI or it is not available in the PATH") } return nil } -func downloadCronCapability(ghToken string) (string, error) { - content, err := downloadGHAssetFromLatestRelease("smartcontractkit", "capabilities", test_env.AUTOMATIC_LATEST_TAG, cronCapabilityAssetFile, ghToken) +func downloadCronCapability(ghToken, version string) (string, error) { + content, err := downloadGHAssetFromRelease("smartcontractkit", "capabilities", version, cronCapabilityAssetFile, ghToken) if err != nil { return "", err } @@ -334,10 +367,12 @@ func downloadCronCapability(ghToken string) (string, error) { return fileName, nil } -func validateInputsAndEnvVars(t *testing.T, testConfig *WorkflowTestConfig) { +func validateInputsAndEnvVars(t *testing.T, in *WorkflowTestConfig) { require.NotEmpty(t, os.Getenv("PRIVATE_KEY"), "PRIVATE_KEY env var must be set") - if !testConfig.WorkflowConfig.UseChainlinkCLI { - require.True(t, testConfig.WorkflowConfig.UseExising, "if you are not using chainlink-cli you must use an existing workflow") + require.NotEmpty(t, in.WorkflowConfig.DependenciesConfig, "dependencies config must be set") + + if !in.WorkflowConfig.UseCRECLI { + require.False(t, in.WorkflowConfig.ShouldCompileNewWorkflow, "if you are not using CRE CLI you cannot compile a new workflow") } var ghReadToken string @@ -354,13 +389,13 @@ func validateInputsAndEnvVars(t *testing.T, testConfig *WorkflowTestConfig) { /* This test can be run in two modes: 1. `existing` mode: it uses a workflow binary (and configuration) file that is already uploaded to Gist - 2. `new` mode: it compiles a new workflow binary and uploads it to Gist + 2. `compile` mode: it compiles a new workflow binary and uploads it to Gist For the `new` mode to work, the `GITHUB_API_TOKEN` env var must be set to a token that has `gist:read` and `gist:write` permissions, but this permissions are tied to account not to repository. Currently, we have no service account in the CI at all. And using a token that's tied to personal account of a developer is not a good idea. So, for now, we are only allowing the `existing` mode in CI. */ - require.True(t, testConfig.WorkflowConfig.UseExising, "only existing workflow can be used in CI as of now due to issues with generating a gist read:write token") + require.False(t, in.WorkflowConfig.ShouldCompileNewWorkflow, "you cannot compile a new workflow in the CI as of now due to issues with generating a gist write token") // we use this special function to subsitute a placeholder env variable with the actual environment variable name // it is defined in .github/e2e-tests.yml as '{{ env.GITHUB_API_TOKEN }}' @@ -370,27 +405,28 @@ func validateInputsAndEnvVars(t *testing.T, testConfig *WorkflowTestConfig) { } require.NotEmpty(t, ghReadToken, ghReadTokenEnvVarName+" env var must be set") - _, err := downloadCronCapability(ghReadToken) + require.NotEmpty(t, in.WorkflowConfig.DependenciesConfig.CapabiltiesVersion, "capabilities_version must be set in the dependencies config") + + _, err := downloadCronCapability(ghReadToken, in.WorkflowConfig.DependenciesConfig.CapabiltiesVersion) require.NoError(t, err, "failed to download cron capability. Make sure token has content:read permissions to the capabilities repo") - if testConfig.WorkflowConfig.UseChainlinkCLI { - if !isInstalled("chainlink-cli") { - err = downloadAndInstallChainlinkCLI(ghReadToken) - require.NoError(t, err, "failed to download and install chainlink-cli. Make sure token has content:read permissions to the dev-platform repo") - } + if in.WorkflowConfig.UseCRECLI { + require.NotEmpty(t, in.WorkflowConfig.DependenciesConfig.CRECLIVersion, "chainlink_cli_version must be set in the dependencies config") + + err = downloadAndInstallChainlinkCLI(ghReadToken, in.WorkflowConfig.DependenciesConfig.CRECLIVersion) + require.NoError(t, err, "failed to download and install CRE CLI. Make sure token has content:read permissions to the dev-platform repo") - if !testConfig.WorkflowConfig.UseExising { + if in.WorkflowConfig.ShouldCompileNewWorkflow { gistWriteToken := os.Getenv("GIST_WRITE_TOKEN") - require.NotEmpty(t, gistWriteToken, "GIST_WRITE_TOKEN must be set to use chainlink-cli to compile workflows. It requires gist:read and gist:write permissions") + require.NotEmpty(t, gistWriteToken, "GIST_WRITE_TOKEN must be set to use CRE CLI to compile workflows. It requires gist:read and gist:write permissions") err := os.Setenv("GITHUB_API_TOKEN", gistWriteToken) require.NoError(t, err, "failed to set GITHUB_API_TOKEN env var") - } else { - require.NotEmpty(t, testConfig.WorkflowConfig.ChainlinkCLI.FolderLocation, "folder_location must be set in the chainlink_cli config") + require.NotEmpty(t, in.WorkflowConfig.WorkflowFolderLocation, "workflow_folder_location must be set, when compiling new workflow") } } // make sure the feed id is in the correct format - testConfig.WorkflowConfig.FeedID = strings.TrimPrefix(testConfig.WorkflowConfig.FeedID, "0x") + in.WorkflowConfig.FeedID = strings.TrimPrefix(in.WorkflowConfig.FeedID, "0x") } // copied from Bala's unmerged PR: https://github.com/smartcontractkit/chainlink/pull/15751 @@ -660,13 +696,13 @@ func prepareFeedsConsumer(t *testing.T, testLogger zerolog.Logger, ctfEnv *deplo } func registerWorkflowDirectly(t *testing.T, in *WorkflowTestConfig, sc *seth.Client, workflowRegistryAddr common.Address, donID uint32, workflowName string) { - require.NotEmpty(t, in.WorkflowConfig.Existing.BinaryURL) - workFlowData, err := downloadAndDecode(in.WorkflowConfig.Existing.BinaryURL) + require.NotEmpty(t, in.WorkflowConfig.CompiledWorkflowConfig.BinaryURL) + workFlowData, err := downloadAndDecode(in.WorkflowConfig.CompiledWorkflowConfig.BinaryURL) require.NoError(t, err, "failed to download and decode workflow binary") var configData []byte - if in.WorkflowConfig.Existing.ConfigURL != "" { - configData, err = download(in.WorkflowConfig.Existing.ConfigURL) + if in.WorkflowConfig.CompiledWorkflowConfig.ConfigURL != "" { + configData, err = download(in.WorkflowConfig.CompiledWorkflowConfig.ConfigURL) require.NoError(t, err, "failed to download workflow config") } @@ -678,12 +714,12 @@ func registerWorkflowDirectly(t *testing.T, in *WorkflowTestConfig, sc *seth.Cli require.NoError(t, err, "failed to create workflow registry instance") // use non-encoded workflow name - _, decodeErr := sc.Decode(workflowRegistryInstance.RegisterWorkflow(sc.NewTXOpts(), workflowName, [32]byte(common.Hex2Bytes(workflowID)), donID, uint8(0), in.WorkflowConfig.Existing.BinaryURL, in.WorkflowConfig.Existing.ConfigURL, "")) + _, decodeErr := sc.Decode(workflowRegistryInstance.RegisterWorkflow(sc.NewTXOpts(), workflowName, [32]byte(common.Hex2Bytes(workflowID)), donID, uint8(0), in.WorkflowConfig.CompiledWorkflowConfig.BinaryURL, in.WorkflowConfig.CompiledWorkflowConfig.ConfigURL, "")) require.NoError(t, decodeErr, "failed to register workflow") } //revive:disable // ignore confusing-results -func compileWorkflowWithChainlinkCli(t *testing.T, in *WorkflowTestConfig, feedsConsumerAddress common.Address, feedID string, settingsFile *os.File) (string, string) { +func compileWorkflowWithCRECLI(t *testing.T, in *WorkflowTestConfig, feedsConsumerAddress common.Address, feedID string, settingsFile *os.File) (string, string) { configFile, err := os.CreateTemp("", "config.json") require.NoError(t, err, "failed to create workflow config file") @@ -712,10 +748,12 @@ func compileWorkflowWithChainlinkCli(t *testing.T, in *WorkflowTestConfig, feeds var outputBuffer bytes.Buffer - compileCmd := exec.Command("chainlink-cli", "workflow", "compile", "-S", settingsFile.Name(), "-c", configFile.Name(), "main.go") // #nosec G204 + // the CLI expects the workflow code to be located in the same directory as its `go.mod`` file. That's why we assume that the file, which + // contains the entrypoint method is always named `main.go`. This is a limitation of the CLI, which we can't change. + compileCmd := exec.Command(CRECLICommand, "workflow", "compile", "-S", settingsFile.Name(), "-c", configFile.Name(), "main.go") // #nosec G204 compileCmd.Stdout = &outputBuffer compileCmd.Stderr = &outputBuffer - compileCmd.Dir = *in.WorkflowConfig.ChainlinkCLI.FolderLocation + compileCmd.Dir = *in.WorkflowConfig.WorkflowFolderLocation err = compileCmd.Start() require.NoError(t, err, "failed to start compile command") @@ -740,12 +778,12 @@ func compileWorkflowWithChainlinkCli(t *testing.T, in *WorkflowTestConfig, feeds return workflowGistURL, workflowConfigURL } -func preapreChainlinkCliSettingsFile(t *testing.T, sc *seth.Client, capRegAddr, workflowRegistryAddr common.Address, donID uint32, chainSelector uint64, rpcHTTPURL string) *os.File { - // create chainlink-cli settings file - settingsFile, err := os.CreateTemp("", ".chainlink-cli-settings.yaml") - require.NoError(t, err, "failed to create chainlink-cli settings file") +func preapreCRECLISettingsFile(t *testing.T, sc *seth.Client, capRegAddr, workflowRegistryAddr common.Address, donID uint32, chainSelector uint64, rpcHTTPURL string) *os.File { + // create CRE CLI settings file + settingsFile, err := os.CreateTemp("", CRECLISettingsFileName) + require.NoError(t, err, "failed to create CRE CLI settings file") - settings := ChainlinkCliSettings{ + settings := CRECLISettings{ DevPlatform: DevPlatform{ CapabilitiesRegistryAddress: capRegAddr.Hex(), DonID: donID, @@ -781,10 +819,10 @@ func preapreChainlinkCliSettingsFile(t *testing.T, sc *seth.Client, capRegAddr, } settingsMarshalled, err := yaml.Marshal(settings) - require.NoError(t, err, "failed to marshal chainlink-cli settings") + require.NoError(t, err, "failed to marshal CRE CLI settings") _, err = settingsFile.Write(settingsMarshalled) - require.NoError(t, err, "failed to write chainlink-cli settings file") + require.NoError(t, err, "failed to write %s settings file", CRECLISettingsFileName) return settingsFile } @@ -792,39 +830,39 @@ func preapreChainlinkCliSettingsFile(t *testing.T, sc *seth.Client, capRegAddr, func registerWorkflow(t *testing.T, in *WorkflowTestConfig, sc *seth.Client, capRegAddr, workflowRegistryAddr, feedsConsumerAddress common.Address, donID uint32, chainSelector uint64, workflowName, pkey, rpcHTTPURL string) { // Register workflow directly using the provided binary and config URLs // This is a legacy solution, probably we can remove it soon - if in.WorkflowConfig.UseExising && !in.WorkflowConfig.UseChainlinkCLI { + if !in.WorkflowConfig.ShouldCompileNewWorkflow && !in.WorkflowConfig.UseCRECLI { registerWorkflowDirectly(t, in, sc, workflowRegistryAddr, donID, workflowName) return } - // These two env vars are required by the chainlink-cli + // These two env vars are required by the CRE CLI err := os.Setenv("WORKFLOW_OWNER_ADDRESS", sc.MustGetRootKeyAddress().Hex()) require.NoError(t, err, "failed to set WORKFLOW_OWNER_ADDRESS env var") err = os.Setenv("ETH_PRIVATE_KEY", pkey) require.NoError(t, err, "failed to set ETH_PRIVATE_KEY env var") - // create chainlink-cli settings file - settingsFile := preapreChainlinkCliSettingsFile(t, sc, capRegAddr, workflowRegistryAddr, donID, chainSelector, rpcHTTPURL) + // create CRE CLI settings file + settingsFile := preapreCRECLISettingsFile(t, sc, capRegAddr, workflowRegistryAddr, donID, chainSelector, rpcHTTPURL) var workflowGistURL string var workflowConfigURL string // compile and upload the workflow, if we are not using an existing one - if !in.WorkflowConfig.UseExising { - workflowGistURL, workflowConfigURL = compileWorkflowWithChainlinkCli(t, in, feedsConsumerAddress, in.WorkflowConfig.FeedID, settingsFile) + if in.WorkflowConfig.ShouldCompileNewWorkflow { + workflowGistURL, workflowConfigURL = compileWorkflowWithCRECLI(t, in, feedsConsumerAddress, in.WorkflowConfig.FeedID, settingsFile) } else { - workflowGistURL = in.WorkflowConfig.Existing.BinaryURL - workflowConfigURL = in.WorkflowConfig.Existing.ConfigURL + workflowGistURL = in.WorkflowConfig.CompiledWorkflowConfig.BinaryURL + workflowConfigURL = in.WorkflowConfig.CompiledWorkflowConfig.ConfigURL } // register the workflow - registerCmd := exec.Command("chainlink-cli", "workflow", "register", workflowName, "-b", workflowGistURL, "-c", workflowConfigURL, "-S", settingsFile.Name(), "-v") + registerCmd := exec.Command(CRECLICommand, "workflow", "register", workflowName, "-b", workflowGistURL, "-c", workflowConfigURL, "-S", settingsFile.Name(), "-v") registerCmd.Stdout = os.Stdout registerCmd.Stderr = os.Stderr err = registerCmd.Run() - require.NoError(t, err, "failed to register workflow using chainlink-cli") + require.NoError(t, err, "failed to register workflow using CRE CLI") } func startNodes(t *testing.T, in *WorkflowTestConfig, bc *blockchain.Output) *ns.Output { @@ -1596,7 +1634,6 @@ func logTestInfo(l zerolog.Logger, feedId, workflowName, feedConsumerAddr, forwa Do not use this test as a template for your tests. It's hacky, since we were working under time pressure. We will soon refactor it follow best practices and a golden example. Apart from its structure what is currently missing is: - using Job Distribution to create jobs for the nodes -- using only `chainlink-cli` to register the workflow (it's there, but doesn't work in CI due to insufficient Github token permissions) - using a mock service to provide the feed data */ func TestKeystoneWithOCR3Workflow(t *testing.T) { @@ -1657,7 +1694,7 @@ func TestKeystoneWithOCR3Workflow(t *testing.T) { // Deploy and configure Keystone Feeds Consumer contract feedsConsumerAddress := prepareFeedsConsumer(t, testLogger, ctfEnv, chainSelector, sc, keystoneContractSet.Forwarder.Address(), in.WorkflowConfig.WorkflowName) - // Register the workflow (either via chainlink-cli or by calling the workflow registry directly) + // Register the workflow (either via CRE CLI or by calling the workflow registry directly) registerWorkflow(t, in, sc, keystoneContractSet.CapabilitiesRegistry.Address(), workflowRegistryAddr, feedsConsumerAddress, in.WorkflowConfig.DonID, chainSelector, in.WorkflowConfig.WorkflowName, pkey, bc.Nodes[0].HostHTTPUrl) // Create OCR3 and capability jobs for each node without JD From 42e134ff1acd16b262f52456e2c36c4bc923da36 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 3 Feb 2025 11:00:44 -0600 Subject: [PATCH 39/43] golangci-lint run --fix (#16190) * core/scripts: golangci-lint run --fix * deployment: golangci-lint run --fix * dashboard-lib: golangci-lint run --fix --- core/scripts/chaincli/handler/debug.go | 2 +- core/scripts/common/avalanche.go | 2 +- core/scripts/common/helpers.go | 2 +- .../scripts/common/vrf/constants/constants.go | 4 +- core/scripts/common/vrf/setup-envs/main.go | 6 +- ...deploy_initialize_capabilities_registry.go | 1 - core/scripts/vrfv2/revert-reason/main.go | 2 +- .../vrfv2/testnet/v2scripts/super_scripts.go | 84 +++++++++---------- .../testnet/v2plusscripts/super_scripts.go | 2 +- .../core-node-components/component.go | 2 +- dashboard-lib/k8s-pods/component.go | 1 - deployment/ccip/changeset/cs_deploy_chain.go | 1 + .../changeset/testhelpers/test_helpers.go | 1 - .../keystone/changeset/internal/deploy.go | 5 +- .../keystone/changeset/internal/types.go | 1 + .../keystone/changeset/internal/update_don.go | 1 + .../changeset/update_node_capabilities.go | 1 - 17 files changed, 59 insertions(+), 59 deletions(-) diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index eb7d34ccae8..5bfac87a08d 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -564,7 +564,7 @@ func mustUpkeepWorkID(upkeepID *big.Int, trigger ocr2keepers.Trigger) [32]byte { } var result [32]byte - copy(result[:], workIDBytes[:]) + copy(result[:], workIDBytes) return result } diff --git a/core/scripts/common/avalanche.go b/core/scripts/common/avalanche.go index 8699463c365..b0d94e52429 100644 --- a/core/scripts/common/avalanche.go +++ b/core/scripts/common/avalanche.go @@ -79,7 +79,7 @@ func (b *AvaBloom) UnmarshalText(input []byte) error { // bloomValues returns the bytes (index-value pairs) to set for the given data func bloomValues(data []byte, hashbuf []byte) (uint, byte, uint, byte, uint, byte) { sha := crypto.NewKeccakState() - sha.Write(data) //nolint:errcheck + sha.Write(data) sha.Read(hashbuf) //nolint:errcheck // The actual bits to flip v1 := byte(1 << (hashbuf[1] & 0x7)) diff --git a/core/scripts/common/helpers.go b/core/scripts/common/helpers.go index f852c88de5b..fed8249e550 100644 --- a/core/scripts/common/helpers.go +++ b/core/scripts/common/helpers.go @@ -506,7 +506,7 @@ func GetRlpHeaders(env Environment, blockNumbers []*big.Int, getParentBlocks boo // Sanity check - can be un-commented if storeVerifyHeader is failing due to unexpected // blockhash. - //bh := crypto.Keccak256Hash(rlpHeader) + // bh := crypto.Keccak256Hash(rlpHeader) //fmt.Println("Calculated BH:", bh.String(), // "fetched BH:", h.Hash(), // "block number:", new(big.Int).Set(blockNum).Add(blockNum, offset).String()) diff --git a/core/scripts/common/vrf/constants/constants.go b/core/scripts/common/vrf/constants/constants.go index 2a064593986..350a7ef8a24 100644 --- a/core/scripts/common/vrf/constants/constants.go +++ b/core/scripts/common/vrf/constants/constants.go @@ -17,7 +17,7 @@ var ( StalenessSeconds = int64(86400) GasAfterPayment = int64(33285) - //vrfv2 + // vrfv2 FlatFeeTier1 = int64(500) FlatFeeTier2 = int64(500) FlatFeeTier3 = int64(500) @@ -28,7 +28,7 @@ var ( ReqsForTier4 = int64(0) ReqsForTier5 = int64(0) - //vrfv2plus + // vrfv2plus FlatFeeNativePPM = uint32(500) FlatFeeLinkDiscountPPM = uint32(100) NativePremiumPercentage = uint8(1) diff --git a/core/scripts/common/vrf/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go index f89b91db063..8565474ee9b 100644 --- a/core/scripts/common/vrf/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -323,14 +323,14 @@ func main() { node := node client, app := connectToNode(&node.URL, output, node.CredsFile) - //GET ALL JOBS + // GET ALL JOBS jobIDs := getAllJobIDs(client, app, output) - //DELETE ALL EXISTING JOBS + // DELETE ALL EXISTING JOBS for _, jobID := range jobIDs { deleteJob(jobID, client, app, output) } - //CREATE JOBS + // CREATE JOBS switch key { case model.VRFPrimaryNodeName: diff --git a/core/scripts/keystone/src/05_deploy_initialize_capabilities_registry.go b/core/scripts/keystone/src/05_deploy_initialize_capabilities_registry.go index 203c473a4b7..278a7e54a5d 100644 --- a/core/scripts/keystone/src/05_deploy_initialize_capabilities_registry.go +++ b/core/scripts/keystone/src/05_deploy_initialize_capabilities_registry.go @@ -269,7 +269,6 @@ func (c *deployAndInitializeCapabilitiesRegistryCommand) Run(args []string) { if err != nil { log.Printf("workflowDON: failed to AddDON: %s", err) } - } func deployCapabilitiesRegistry(env helpers.Environment) *kcr.CapabilitiesRegistry { diff --git a/core/scripts/vrfv2/revert-reason/main.go b/core/scripts/vrfv2/revert-reason/main.go index 20f3cd68986..60414659204 100644 --- a/core/scripts/vrfv2/revert-reason/main.go +++ b/core/scripts/vrfv2/revert-reason/main.go @@ -21,7 +21,7 @@ func main() { ec, err := ethclient.Dial("TODO") panicErr(err) txHash := "0xedeeecf6bd763ecc82b5dff31e073af9cc4cf8a4b47708df526ba61cf0201d25" // non-custom on goerli - //txHash := "0x6ec8a69657600786f0b31726f36287e80196029e60f8365528d4d540a6f70763" // custom error on mainnet + // txHash := "0x6ec8a69657600786f0b31726f36287e80196029e60f8365528d4d540a6f70763" // custom error on mainnet tx, _, err := ec.TransactionByHash(context.Background(), gethCommon.HexToHash(txHash)) panicErr(err) re, err := ec.TransactionReceipt(context.Background(), gethCommon.HexToHash(txHash)) diff --git a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index f392a35f246..b56e423f0a3 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -296,7 +296,7 @@ func VRFV2DeployUniverse( if len(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) > 0 { fmt.Println("\nRegistering proving key...") - //NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able + // NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able // easily withdraw funds from Coordinator contract back to EOA account RegisterCoordinatorProvingKey(e, *coordinator, vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, vrfKeyRegistrationConfig.RegisterAgainstAddress) @@ -354,19 +354,19 @@ func VRFV2DeployUniverse( formattedVrfPrimaryJobSpec := fmt.Sprintf( jobs.VRFV2JobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled - coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier - coordinatorJobSpecConfig.RevertsPipelineEnabled, //revertsPipelineEnabled - compressedPkHex, //publicKey - coordinatorConfig.MinConfs, //minIncomingConfirmations - e.ChainID, //evmChainID - strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses - coordinatorJobSpecConfig.PollPeriod, //pollPeriod - coordinatorJobSpecConfig.RequestTimeout, //requestTimeout + contractAddresses.CoordinatorAddress, // coordinatorAddress + contractAddresses.BatchCoordinatorAddress, // batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, // batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, // batchFulfillmentGasMultiplier + coordinatorJobSpecConfig.RevertsPipelineEnabled, // revertsPipelineEnabled + compressedPkHex, // publicKey + coordinatorConfig.MinConfs, // minIncomingConfirmations + e.ChainID, // evmChainID + strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), // fromAddresses + coordinatorJobSpecConfig.PollPeriod, // pollPeriod + coordinatorJobSpecConfig.RequestTimeout, // requestTimeout contractAddresses.CoordinatorAddress, - coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier + coordinatorJobSpecConfig.EstimateGasMultiplier, // estimateGasMultiplier simulationBlock, func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { @@ -387,19 +387,19 @@ func VRFV2DeployUniverse( formattedVrfBackupJobSpec := fmt.Sprintf( jobs.VRFV2JobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled - coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier - coordinatorJobSpecConfig.RevertsPipelineEnabled, //revertsPipelineEnabled - compressedPkHex, //publicKey - 100, //minIncomingConfirmations - e.ChainID, //evmChainID - strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses - coordinatorJobSpecConfig.PollPeriod, //pollPeriod - coordinatorJobSpecConfig.RequestTimeout, //requestTimeout + contractAddresses.CoordinatorAddress, // coordinatorAddress + contractAddresses.BatchCoordinatorAddress, // batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, // batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, // batchFulfillmentGasMultiplier + coordinatorJobSpecConfig.RevertsPipelineEnabled, // revertsPipelineEnabled + compressedPkHex, // publicKey + 100, // minIncomingConfirmations + e.ChainID, // evmChainID + strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), // fromAddresses + coordinatorJobSpecConfig.PollPeriod, // pollPeriod + coordinatorJobSpecConfig.RequestTimeout, // requestTimeout contractAddresses.CoordinatorAddress, - coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier + coordinatorJobSpecConfig.EstimateGasMultiplier, // estimateGasMultiplier simulationBlock, func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { @@ -420,33 +420,33 @@ func VRFV2DeployUniverse( formattedBHSJobSpec := fmt.Sprintf( jobs.BHSJobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - bhsJobSpecConfig.WaitBlocks, //waitBlocks - bhsJobSpecConfig.LookBackBlocks, //lookbackBlocks - contractAddresses.BhsContractAddress, //bhs address + contractAddresses.CoordinatorAddress, // coordinatorAddress + bhsJobSpecConfig.WaitBlocks, // waitBlocks + bhsJobSpecConfig.LookBackBlocks, // lookbackBlocks + contractAddresses.BhsContractAddress, // bhs address bhsJobSpecConfig.PollPeriod, bhsJobSpecConfig.RunTimeout, - e.ChainID, //chain id - strings.Join(util.MapToAddressArr(nodesMap[model.BHSNodeName].SendingKeys), "\",\""), //sending addresses + e.ChainID, // chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHSNodeName].SendingKeys), "\",\""), // sending addresses ) formattedBHSBackupJobSpec := fmt.Sprintf( jobs.BHSJobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - 100, //waitBlocks - 200, //lookbackBlocks - contractAddresses.BhsContractAddress, //bhs adreess - e.ChainID, //chain id - strings.Join(util.MapToAddressArr(nodesMap[model.BHSBackupNodeName].SendingKeys), "\",\""), //sending addresses + contractAddresses.CoordinatorAddress, // coordinatorAddress + 100, // waitBlocks + 200, // lookbackBlocks + contractAddresses.BhsContractAddress, // bhs adreess + e.ChainID, // chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHSBackupNodeName].SendingKeys), "\",\""), // sending addresses ) formattedBHFJobSpec := fmt.Sprintf( jobs.BHFJobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BhsContractAddress, //bhs adreess - contractAddresses.BatchBHSAddress, //batchBHS - e.ChainID, //chain id - strings.Join(util.MapToAddressArr(nodesMap[model.BHFNodeName].SendingKeys), "\",\""), //sending addresses + contractAddresses.CoordinatorAddress, // coordinatorAddress + contractAddresses.BhsContractAddress, // bhs adreess + contractAddresses.BatchBHSAddress, // batchBHS + e.ChainID, // chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHFNodeName].SendingKeys), "\",\""), // sending addresses ) fmt.Println( diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index dd0186144d4..1f7294e574e 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -755,7 +755,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, if len(vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) > 0 { fmt.Println("\nRegistering proving key...") - //NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able + // NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able // easily withdraw funds from Coordinator contract back to EOA account RegisterCoordinatorProvingKey(e, *coordinator, vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, provingKeyMaxGasPrice) diff --git a/dashboard-lib/core-node-components/component.go b/dashboard-lib/core-node-components/component.go index 47e23c073ba..5452a1c257f 100644 --- a/dashboard-lib/core-node-components/component.go +++ b/dashboard-lib/core-node-components/component.go @@ -114,7 +114,7 @@ func generalInfoRow(p Props) []dashboard.Option { ), timeseries.WithPrometheusTarget( `up{`+p.PlatformOpts.LabelQuery+`}`, - //prometheus.Legend(""), + // prometheus.Legend(""), prometheus.Legend("Team: {{team}} env: {{env}} cluster: {{cluster}} namespace: {{namespace}} job: {{job}} blockchain: {{blockchain}} product: {{product}} networkType: {{network_type}} component: {{component}} service: {{service}}"), ), ), diff --git a/dashboard-lib/k8s-pods/component.go b/dashboard-lib/k8s-pods/component.go index df9a6ac6a69..559a89f4538 100644 --- a/dashboard-lib/k8s-pods/component.go +++ b/dashboard-lib/k8s-pods/component.go @@ -68,7 +68,6 @@ func logsRow(p Props) []dashboard.Option { ), ), } - } func New(p Props) []dashboard.Option { diff --git a/deployment/ccip/changeset/cs_deploy_chain.go b/deployment/ccip/changeset/cs_deploy_chain.go index b8305916947..f73ee8c726a 100644 --- a/deployment/ccip/changeset/cs_deploy_chain.go +++ b/deployment/ccip/changeset/cs_deploy_chain.go @@ -15,6 +15,7 @@ import ( solBinary "github.com/gagliardetto/binary" solRpc "github.com/gagliardetto/solana-go/rpc" chainsel "github.com/smartcontractkit/chain-selectors" + solRouter "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router" solCommonUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" solState "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/state" diff --git a/deployment/ccip/changeset/testhelpers/test_helpers.go b/deployment/ccip/changeset/testhelpers/test_helpers.go index b2a5dc26653..75d190ae3f0 100644 --- a/deployment/ccip/changeset/testhelpers/test_helpers.go +++ b/deployment/ccip/changeset/testhelpers/test_helpers.go @@ -541,7 +541,6 @@ func AddLane( e.Env, err = commoncs.ApplyChangesets(t, e.Env, e.TimelockContracts(t), changesets) require.NoError(t, err) - } // RemoveLane removes a lane between the source and destination chains in the deployed environment. diff --git a/deployment/keystone/changeset/internal/deploy.go b/deployment/keystone/changeset/internal/deploy.go index ef8f138e743..eed83f24e44 100644 --- a/deployment/keystone/changeset/internal/deploy.go +++ b/deployment/keystone/changeset/internal/deploy.go @@ -18,11 +18,12 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" chainsel "github.com/smartcontractkit/chain-selectors" - capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" - "github.com/smartcontractkit/chainlink-common/pkg/logger" "golang.org/x/exp/maps" "google.golang.org/protobuf/proto" + capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment" capabilities_registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" kf "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/forwarder_1_0_0" diff --git a/deployment/keystone/changeset/internal/types.go b/deployment/keystone/changeset/internal/types.go index 1b1faccca5b..d803a652c5f 100644 --- a/deployment/keystone/changeset/internal/types.go +++ b/deployment/keystone/changeset/internal/types.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" + capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" chainsel "github.com/smartcontractkit/chain-selectors" diff --git a/deployment/keystone/changeset/internal/update_don.go b/deployment/keystone/changeset/internal/update_don.go index 8c7e77608fb..965f926da31 100644 --- a/deployment/keystone/changeset/internal/update_don.go +++ b/deployment/keystone/changeset/internal/update_don.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" diff --git a/deployment/keystone/changeset/update_node_capabilities.go b/deployment/keystone/changeset/update_node_capabilities.go index 5f383936231..bf869416604 100644 --- a/deployment/keystone/changeset/update_node_capabilities.go +++ b/deployment/keystone/changeset/update_node_capabilities.go @@ -108,7 +108,6 @@ func (req *MutateNodeCapabilitiesRequest) updateNodeCapabilitiesImplRequest(e de // UpdateNodeCapabilities updates the capabilities of nodes in the registry func UpdateNodeCapabilities(env deployment.Environment, req *UpdateNodeCapabilitiesRequest) (deployment.ChangesetOutput, error) { - c, contractSet, err := req.updateNodeCapabilitiesImplRequest(env) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to convert request: %w", err) From a2d251949260dee0a94ef2c5984afe7b937bba5c Mon Sep 17 00:00:00 2001 From: Anirudh Warrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Mon, 3 Feb 2025 22:18:44 +0400 Subject: [PATCH 40/43] update cre version in capabilities test (#16195) --- integration-tests/smoke/capabilities/environment-ci.toml | 2 +- integration-tests/smoke/capabilities/environment.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/smoke/capabilities/environment-ci.toml b/integration-tests/smoke/capabilities/environment-ci.toml index 968e1fabd3e..fc995e42e26 100644 --- a/integration-tests/smoke/capabilities/environment-ci.toml +++ b/integration-tests/smoke/capabilities/environment-ci.toml @@ -17,7 +17,7 @@ [workflow_config.dependencies] capabilities_version = "v1.0.0-alpha" - cre_cli_version = "v1.0.2" + cre_cli_version = "v0.0.2" [workflow_config.compiled_config] binary_url = "https://gist.githubusercontent.com/Tofel/8a39af5b68c213d2200446c175b5c99e/raw/cb7b2a56b37e333fe0bdce07b79538c4ce332f5f/binary.wasm.br" diff --git a/integration-tests/smoke/capabilities/environment.toml b/integration-tests/smoke/capabilities/environment.toml index b6f648c7136..9d01472175e 100644 --- a/integration-tests/smoke/capabilities/environment.toml +++ b/integration-tests/smoke/capabilities/environment.toml @@ -19,7 +19,7 @@ [workflow_config.dependencies] capabilities_version = "v1.0.0-alpha" - cre_cli_version = "v1.0.2" + cre_cli_version = "v0.0.2" [workflow_config.compiled_config] binary_url = "https://gist.githubusercontent.com/Tofel/8a39af5b68c213d2200446c175b5c99e/raw/cb7b2a56b37e333fe0bdce07b79538c4ce332f5f/binary.wasm.br" From 9e7579f98898f9e095577597e682f74f6b909ed9 Mon Sep 17 00:00:00 2001 From: Bartek Tofel Date: Mon, 3 Feb 2025 19:40:57 +0100 Subject: [PATCH 41/43] [TT-1984] Use job distributor in keystone smoke test + FMS change (#16169) * create all jobs with the job distributor * add standardcapabilities and gateway jobs to the FMS * fix lints * add changeset * fix changeset * one more time with lints * simplify and look for gateway job only by name --- .changeset/yellow-dodos-run.md | 5 + core/services/feeds/service.go | 20 +++ core/services/job/job_orm_test.go | 164 +++++++++++++++-- core/services/job/mocks/orm.go | 114 ++++++++++++ core/services/job/models.go | 16 ++ core/services/job/orm.go | 29 ++- core/testdata/testspecs/v2_specs.go | 74 +++++++- .../smoke/capabilities/environment.toml | 2 +- .../smoke/capabilities/workflow_test.go | 169 ++++++++++++------ 9 files changed, 528 insertions(+), 65 deletions(-) create mode 100644 .changeset/yellow-dodos-run.md diff --git a/.changeset/yellow-dodos-run.md b/.changeset/yellow-dodos-run.md new file mode 100644 index 00000000000..eddb0bf369d --- /dev/null +++ b/.changeset/yellow-dodos-run.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#added Add support for 'standardcapabilities' and 'gateway' jobs to the FMS diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index 6bbfe1fe035..f99fde65b63 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -24,6 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" @@ -31,6 +32,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr" ocr2 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" + "github.com/smartcontractkit/chainlink/v2/core/services/standardcapabilities" "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/workflows" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" @@ -891,6 +893,20 @@ func (s *service) ApproveSpec(ctx context.Context, id int64, force bool) error { if txerr != nil && !errors.Is(txerr, sql.ErrNoRows) { return fmt.Errorf("failed while checking for existing ccip job: %w", txerr) } + case job.StandardCapabilities: + existingJobID, txerr = tx.jobORM.FindStandardCapabilityJobID(ctx, *j.StandardCapabilitiesSpec) + // Return an error if the repository errors. If there is a not found + // error we want to continue with approving the job. + if txerr != nil && !errors.Is(txerr, sql.ErrNoRows) { + return fmt.Errorf("failed while checking for existing standard capabilities job: %w", txerr) + } + case job.Gateway: + existingJobID, txerr = tx.jobORM.FindGatewayJobID(ctx, *j.GatewaySpec) + // Return an error if the repository errors. If there is a not found + // error we want to continue with approving the job. + if txerr != nil && !errors.Is(txerr, sql.ErrNoRows) { + return fmt.Errorf("failed while checking for existing gateway job: %w", txerr) + } case job.Stream: existingJobID, txerr = tx.jobORM.FindJobIDByStreamID(ctx, *j.StreamID) // Return an error if the repository errors. If there is a not found @@ -1304,6 +1320,10 @@ func (s *service) generateJob(ctx context.Context, spec string) (*job.Job, error js, err = ccip.ValidatedCCIPSpec(spec) case job.Stream: js, err = streams.ValidatedStreamSpec(spec) + case job.Gateway: + js, err = gateway.ValidatedGatewaySpec(spec) + case job.StandardCapabilities: + js, err = standardcapabilities.ValidatedStandardCapabilitiesSpec(spec) default: return nil, errors.Errorf("unknown job type: %s", jobType) } diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index eb0a7d23ce7..cd010c76215 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -31,6 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/blockheaderfeeder" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -40,6 +41,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay" + "github.com/smartcontractkit/chainlink/v2/core/services/standardcapabilities" "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" @@ -2175,7 +2177,7 @@ func TestORM_CreateJob_OCR2_With_DualTransmission(t *testing.T) { emptyTransmitterAddress := ` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '' ` jb, err = ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), baseJobSpec+emptyTransmitterAddress, nil) @@ -2187,7 +2189,7 @@ func TestORM_CreateJob_OCR2_With_DualTransmission(t *testing.T) { metaNotSliceDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] key1 = 'val1' @@ -2202,7 +2204,7 @@ func TestORM_CreateJob_OCR2_With_DualTransmission(t *testing.T) { hintNotValidDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] hint = ['some-invalid-hint'] @@ -2217,7 +2219,7 @@ func TestORM_CreateJob_OCR2_With_DualTransmission(t *testing.T) { invalidRefundFormatDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] hint = ['calldata','logs'] @@ -2232,7 +2234,7 @@ func TestORM_CreateJob_OCR2_With_DualTransmission(t *testing.T) { invalidRefundAddressFormatDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] hint = ['calldata','logs'] @@ -2247,7 +2249,7 @@ func TestORM_CreateJob_OCR2_With_DualTransmission(t *testing.T) { invalidRefundPercentFormatDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] hint = ['calldata','logs'] @@ -2262,7 +2264,7 @@ func TestORM_CreateJob_OCR2_With_DualTransmission(t *testing.T) { invalidRefundPercentTotalFormatDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] hint = ['calldata','logs'] @@ -2277,7 +2279,7 @@ func TestORM_CreateJob_OCR2_With_DualTransmission(t *testing.T) { completeDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] key1 = ['val1'] @@ -2330,7 +2332,7 @@ func TestORM_CreateJob_KeyLocking(t *testing.T) { completeDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] key1 = ['val1'] @@ -2351,7 +2353,7 @@ func TestORM_CreateJob_KeyLocking(t *testing.T) { completeDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] key1 = ['val1'] @@ -2385,7 +2387,7 @@ func TestORM_CreateJob_KeyLocking(t *testing.T) { completeDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true [relayConfig.dualTransmission] - contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' + contractAddress = '0x613a38AC1659769640aaE063C651F48E0250454C' transmitterAddress = '%s' [relayConfig.dualTransmission.meta] key1 = ['val1'] @@ -2402,3 +2404,143 @@ func TestORM_CreateJob_KeyLocking(t *testing.T) { require.ErrorContains(t, jobORM.CreateJob(ctx, &jb), "cannot be a secondary transmitter address because it's used a primary transmitter in another job") }) } + +func Test_FindGatewayJobID(t *testing.T) { + t.Parallel() + ctx := testutils.Context(t) + + config := configtest.NewTestGeneralConfig(t) + db := pgtest.NewSqlxDB(t) + + keyStore := cltest.NewKeyStore(t, db) + err := keyStore.OCR().Add(ctx, cltest.DefaultOCRKey) + require.NoError(t, err, "failed to add OCR key") + + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) + bridgesORM := bridges.NewORM(db) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) + + gatewayJob, err := gateway.ValidatedGatewaySpec(testspecs.GetGatewaySpec()) + require.NoError(t, err, "failed to validate gateway spec") + + err = orm.CreateJob(ctx, &gatewayJob) + require.NoError(t, err, "failed to create gateway job") + var jobSpec job.Job + err = db.Get(&jobSpec, "SELECT * FROM jobs") + require.NoError(t, err, "failed to get gateway job from db") + + // find only by auth gateway id + gatewayJobSpec := job.GatewaySpec{ + GatewayConfig: job.JSONConfig{ + "ConnectionManagerConfig": map[string]interface{}{ + "AuthGatewayId": "gateway", + }, + }, + } + id, err := orm.FindGatewayJobID(ctx, gatewayJobSpec) + require.NoError(t, err, "failed to find gateway job by auth gateway id") + require.Equal(t, jobSpec.ID, id, "mismatch job id") +} + +func Test_FindGatewayJobID_NoMatch(t *testing.T) { + t.Parallel() + ctx := testutils.Context(t) + + config := configtest.NewTestGeneralConfig(t) + db := pgtest.NewSqlxDB(t) + + keyStore := cltest.NewKeyStore(t, db) + err := keyStore.OCR().Add(ctx, cltest.DefaultOCRKey) + require.NoError(t, err, "failed to add OCR key") + + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) + bridgesORM := bridges.NewORM(db) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) + + gatewayJob, err := gateway.ValidatedGatewaySpec(testspecs.GetGatewaySpec()) + require.NoError(t, err, "failed to validate gateway spec") + + err = orm.CreateJob(ctx, &gatewayJob) + require.NoError(t, err, "failed to create gateway job") + var jobSpec job.Job + err = db.Get(&jobSpec, "SELECT * FROM jobs") + require.NoError(t, err, "failed to get gateway job from db") + + // different auth gateway id + gatewayJobSpec := job.GatewaySpec{ + GatewayConfig: job.JSONConfig{ + "ConnectionManagerConfig": map[string]interface{}{ + "AuthGatewayId": "another_gateway", + }, + }, + } + id, err := orm.FindGatewayJobID(ctx, gatewayJobSpec) + require.Error(t, err, "found gateway job by auth gateway id") + require.Equal(t, int32(0), id, "found non-zero job id") +} + +func Test_FindStandardCapabilityJobID(t *testing.T) { + t.Parallel() + ctx := testutils.Context(t) + + config := configtest.NewTestGeneralConfig(t) + db := pgtest.NewSqlxDB(t) + + keyStore := cltest.NewKeyStore(t, db) + err := keyStore.OCR().Add(ctx, cltest.DefaultOCRKey) + require.NoError(t, err, "failed to add OCR key") + + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) + bridgesORM := bridges.NewORM(db) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) + + stdJob, err := standardcapabilities.ValidatedStandardCapabilitiesSpec(testspecs.GetStandardCapabilitySpec()) + require.NoError(t, err, "failed to validate standard capabilities spec") + + err = orm.CreateJob(ctx, &stdJob) + require.NoError(t, err, "failed to create standard capabilities job") + var jobSpec job.Job + err = db.Get(&jobSpec, "SELECT * FROM jobs") + require.NoError(t, err, "failed to get standard capabilities job from db") + + stdCapJobSpec := job.StandardCapabilitiesSpec{ + Command: "/home/capabilities/some_capability_linux_amd64", + } + + id, err := orm.FindStandardCapabilityJobID(ctx, stdCapJobSpec) + require.NoError(t, err, "failed to find standard capabilities by command") + require.Equal(t, jobSpec.ID, id, "mismatch job id") +} + +func Test_FindStandardCapabilityJobID_NoMatch(t *testing.T) { + t.Parallel() + ctx := testutils.Context(t) + + config := configtest.NewTestGeneralConfig(t) + db := pgtest.NewSqlxDB(t) + + keyStore := cltest.NewKeyStore(t, db) + err := keyStore.OCR().Add(ctx, cltest.DefaultOCRKey) + require.NoError(t, err, "failed to add OCR key") + + pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.JobPipeline().MaxSuccessfulRuns()) + bridgesORM := bridges.NewORM(db) + orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) + + stdJob, err := standardcapabilities.ValidatedStandardCapabilitiesSpec(testspecs.GetStandardCapabilitySpec()) + require.NoError(t, err, "failed to validate standard capabilities spec") + + err = orm.CreateJob(ctx, &stdJob) + require.NoError(t, err, "failed to create standard capabilities job") + var jobSpec job.Job + err = db.Get(&jobSpec, "SELECT * FROM jobs") + require.NoError(t, err, "failed to get standard capabilities job from db") + + stdCapJobSpec := job.StandardCapabilitiesSpec{ + Command: "/home/capabilities/some_other_capability_linux_amd64", + } + + id, err := orm.FindStandardCapabilityJobID(ctx, stdCapJobSpec) + require.Error(t, err, "found standard capabilities with different command") + require.Equal(t, int32(0), id, "found non-zero job id") +} diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index 15e3a4e99b3..2bfd5f3fa84 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -372,6 +372,63 @@ func (_c *ORM_DismissError_Call) RunAndReturn(run func(context.Context, int64) e return _c } +// FindGatewayJobID provides a mock function with given fields: ctx, spec +func (_m *ORM) FindGatewayJobID(ctx context.Context, spec job.GatewaySpec) (int32, error) { + ret := _m.Called(ctx, spec) + + if len(ret) == 0 { + panic("no return value specified for FindGatewayJobID") + } + + var r0 int32 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, job.GatewaySpec) (int32, error)); ok { + return rf(ctx, spec) + } + if rf, ok := ret.Get(0).(func(context.Context, job.GatewaySpec) int32); ok { + r0 = rf(ctx, spec) + } else { + r0 = ret.Get(0).(int32) + } + + if rf, ok := ret.Get(1).(func(context.Context, job.GatewaySpec) error); ok { + r1 = rf(ctx, spec) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ORM_FindGatewayJobID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindGatewayJobID' +type ORM_FindGatewayJobID_Call struct { + *mock.Call +} + +// FindGatewayJobID is a helper method to define mock.On call +// - ctx context.Context +// - spec job.GatewaySpec +func (_e *ORM_Expecter) FindGatewayJobID(ctx interface{}, spec interface{}) *ORM_FindGatewayJobID_Call { + return &ORM_FindGatewayJobID_Call{Call: _e.mock.On("FindGatewayJobID", ctx, spec)} +} + +func (_c *ORM_FindGatewayJobID_Call) Run(run func(ctx context.Context, spec job.GatewaySpec)) *ORM_FindGatewayJobID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(job.GatewaySpec)) + }) + return _c +} + +func (_c *ORM_FindGatewayJobID_Call) Return(_a0 int32, _a1 error) *ORM_FindGatewayJobID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ORM_FindGatewayJobID_Call) RunAndReturn(run func(context.Context, job.GatewaySpec) (int32, error)) *ORM_FindGatewayJobID_Call { + _c.Call.Return(run) + return _c +} + // FindJob provides a mock function with given fields: ctx, id func (_m *ORM) FindJob(ctx context.Context, id int32) (job.Job, error) { ret := _m.Called(ctx, id) @@ -1308,6 +1365,63 @@ func (_c *ORM_FindSpecErrorsByJobIDs_Call) RunAndReturn(run func(context.Context return _c } +// FindStandardCapabilityJobID provides a mock function with given fields: ctx, spec +func (_m *ORM) FindStandardCapabilityJobID(ctx context.Context, spec job.StandardCapabilitiesSpec) (int32, error) { + ret := _m.Called(ctx, spec) + + if len(ret) == 0 { + panic("no return value specified for FindStandardCapabilityJobID") + } + + var r0 int32 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, job.StandardCapabilitiesSpec) (int32, error)); ok { + return rf(ctx, spec) + } + if rf, ok := ret.Get(0).(func(context.Context, job.StandardCapabilitiesSpec) int32); ok { + r0 = rf(ctx, spec) + } else { + r0 = ret.Get(0).(int32) + } + + if rf, ok := ret.Get(1).(func(context.Context, job.StandardCapabilitiesSpec) error); ok { + r1 = rf(ctx, spec) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ORM_FindStandardCapabilityJobID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindStandardCapabilityJobID' +type ORM_FindStandardCapabilityJobID_Call struct { + *mock.Call +} + +// FindStandardCapabilityJobID is a helper method to define mock.On call +// - ctx context.Context +// - spec job.StandardCapabilitiesSpec +func (_e *ORM_Expecter) FindStandardCapabilityJobID(ctx interface{}, spec interface{}) *ORM_FindStandardCapabilityJobID_Call { + return &ORM_FindStandardCapabilityJobID_Call{Call: _e.mock.On("FindStandardCapabilityJobID", ctx, spec)} +} + +func (_c *ORM_FindStandardCapabilityJobID_Call) Run(run func(ctx context.Context, spec job.StandardCapabilitiesSpec)) *ORM_FindStandardCapabilityJobID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(job.StandardCapabilitiesSpec)) + }) + return _c +} + +func (_c *ORM_FindStandardCapabilityJobID_Call) Return(_a0 int32, _a1 error) *ORM_FindStandardCapabilityJobID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ORM_FindStandardCapabilityJobID_Call) RunAndReturn(run func(context.Context, job.StandardCapabilitiesSpec) (int32, error)) *ORM_FindStandardCapabilityJobID_Call { + _c.Call.Return(run) + return _c +} + // FindTaskResultByRunIDAndTaskName provides a mock function with given fields: ctx, runID, taskName func (_m *ORM) FindTaskResultByRunIDAndTaskName(ctx context.Context, runID int64, taskName string) ([]byte, error) { ret := _m.Called(ctx, runID, taskName) diff --git a/core/services/job/models.go b/core/services/job/models.go index d081f08bef0..1a948621e54 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -823,6 +823,22 @@ func (s *GatewaySpec) SetID(value string) error { return nil } +// AuthGatewayID returns AuthGatewayId or empty string, if not found or it's not a string +func (s *GatewaySpec) AuthGatewayID() string { + // not using config.GatewayConfig directly to avoid import cycle + if nsc, ok := s.GatewayConfig["ConnectionManagerConfig"]; ok { + if nscMap, ok := nsc.(map[string]interface{}); ok { + if authGatewayID, ok := nscMap["AuthGatewayId"]; ok { + if authGatewayIDStr, ok := authGatewayID.(string); ok { + return authGatewayIDStr + } + } + } + } + + return "" +} + // EALSpec defines the job spec for the gas station. type EALSpec struct { ID int32 diff --git a/core/services/job/orm.go b/core/services/job/orm.go index d0dc0767afb..8c41bb00b0d 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -78,7 +78,10 @@ type ORM interface { WithDataSource(source sqlutil.DataSource) ORM FindJobIDByWorkflow(ctx context.Context, spec WorkflowSpec) (int32, error) + // TODO rename function to indicate it is CCIP-specific, not generic? FindJobIDByCapabilityNameAndVersion(ctx context.Context, spec CCIPSpec) (int32, error) + FindStandardCapabilityJobID(ctx context.Context, spec StandardCapabilitiesSpec) (int32, error) + FindGatewayJobID(ctx context.Context, spec GatewaySpec) (int32, error) FindJobIDByStreamID(ctx context.Context, streamID uint32) (int32, error) } @@ -821,7 +824,7 @@ func (o *orm) DeleteJob(ctx context.Context, id int32, jobType Type) error { %s ),`, q) } - query += ` + query += ` deleted_job_pipeline_specs AS ( DELETE FROM job_pipeline_specs WHERE job_id IN (SELECT id FROM deleted_jobs) RETURNING pipeline_spec_id ) @@ -1179,6 +1182,30 @@ INNER JOIN ccip_specs ccip on jobs.ccip_spec_id = ccip.id AND ccip.capability_la return } +func (o *orm) FindStandardCapabilityJobID(ctx context.Context, spec StandardCapabilitiesSpec) (jobID int32, err error) { + stmt := ` +SELECT jobs.id FROM jobs +INNER JOIN standardcapabilities_specs sc on jobs.standard_capabilities_spec_id = sc.id AND sc.command = $1 +` + err = o.ds.GetContext(ctx, &jobID, stmt, spec.Command) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + err = fmt.Errorf("error searching for job for standardcapabilities (command) ('%s'): %w", spec.Command, err) + } + return +} + +func (o *orm) FindGatewayJobID(ctx context.Context, spec GatewaySpec) (jobID int32, err error) { + stmt := ` +SELECT jobs.id FROM jobs +INNER JOIN gateway_specs gs on jobs.gateway_spec_id = gs.id +WHERE gs.gateway_config @> jsonb_build_object('ConnectionManagerConfig', jsonb_build_object('AuthGatewayId', $1::text));` + err = o.ds.GetContext(ctx, &jobID, stmt, spec.AuthGatewayID()) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + err = fmt.Errorf("error searching for job for gateway (ConnectionManagerConfig.AuthGatewayId) ('%s'): %w", spec.AuthGatewayID(), err) + } + return +} + // PipelineRunsByJobsIDs returns pipeline runs for multiple jobs, not preloading data func (o *orm) PipelineRunsByJobsIDs(ctx context.Context, ids []int32) (runs []pipeline.Run, err error) { err = o.transact(ctx, false, func(tx *orm) error { diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index ff1f96ce080..e8a58bb4eea 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -186,9 +186,81 @@ schemaVersion = 1 contractID = "0x613a38AC1659769640aaE063C651F48E0250454C" [relayConfig] chainID = 1337 +` + + GatewaySpec = ` +type = "gateway" +schemaVersion = 1 +externalJobID = "%s" +name = "Gateway" +forwardingAllowed = false +[gatewayConfig.ConnectionManagerConfig] +AuthChallengeLen = 10 +AuthGatewayId = "%s" +AuthTimestampToleranceSec = 5 +HeartbeatIntervalSec = 20 +[[gatewayConfig.Dons]] +DonId = "1" +F = 1 +HandlerName = "web-api-capabilities" + [gatewayConfig.Dons.HandlerConfig] + MaxAllowedMessageAgeSec = 1_000 + [gatewayConfig.Dons.HandlerConfig.NodeRateLimiter] + GlobalBurst = 10 + GlobalRPS = 50 + PerSenderBurst = 10 + PerSenderRPS = 10 + [[gatewayConfig.Dons.Members]] + Address = "%s" + Name = "Workflow Node 1" + [[gatewayConfig.Dons.Members]] + Address = "%s" + Name = "Workflow Node 2" + [[gatewayConfig.Dons.Members]] + Address = "%s" + Name = "Workflow Node 3" + [[gatewayConfig.Dons.Members]] + Address = "%s" + Name = "Workflow Node 4" +[gatewayConfig.NodeServerConfig] +HandshakeTimeoutMillis = 1_000 +MaxRequestBytes = 100_000 +Path = "%s" +Port = %d +ReadTimeoutMillis = 1_000 +RequestTimeoutMillis = 10_000 +WriteTimeoutMillis = 1_000 +[gatewayConfig.UserServerConfig] +ContentTypeHeader = "application/jsonrpc" +MaxRequestBytes = 100_000 +Path = "%s" +Port = %d +ReadTimeoutMillis = 1_000 +RequestTimeoutMillis = 10_000 +WriteTimeoutMillis = 1_000 +[gatewayConfig.HTTPClientConfig] +MaxResponseBytes = 100_000_000 +` + + StandardCapabilitySpec = ` +type = "standardcapabilities" +schemaVersion = 1 +externalJobID = "%s" +name = "%s" +forwardingAllowed = false +command = "/home/capabilities/%s" +config = "%s" ` ) +func GetStandardCapabilitySpec() string { + return fmt.Sprintf(StandardCapabilitySpec, uuid.New(), "some-capability", "some_capability_linux_amd64", "") +} + +func GetGatewaySpec() string { + return fmt.Sprintf(GatewaySpec, uuid.New(), "gateway", "0xABA5eDc1a551E55b1A570c0e1f1055e5BE11eca1", "0xABA5eDc1a551E55b1A570c0e1f1055e5BE11eca2", "0xABA5eDc1a551E55b1A570c0e1f1055e5BE11eca3", "0xABA5eDc1a551E55b1A570c0e1f1055e5BE11eca4", "/node", 8080, "/user", 8081) +} + func GetOCRBootstrapSpec() string { return fmt.Sprintf(OCRBootstrapSpec, uuid.New()) } @@ -948,7 +1020,7 @@ targets: - id: "a-target@1.0.0" config: {} ref: "a-target" - inputs: + inputs: consensus_output: $(a-consensus.outputs) ` var OCR2EVMDualTransmissionSpecMinimalTemplate = ` diff --git a/integration-tests/smoke/capabilities/environment.toml b/integration-tests/smoke/capabilities/environment.toml index 9d01472175e..4fe561ca1b5 100644 --- a/integration-tests/smoke/capabilities/environment.toml +++ b/integration-tests/smoke/capabilities/environment.toml @@ -14,7 +14,7 @@ feed_id = "018bfe8840700040000000000000000000000000000000000000000000000000" use_cre_cli = true - should_compile_new_workflow = true + should_compile_new_workflow = false workflow_folder_location = "path-to-folder-with-main.go-of-your-workflow" [workflow_config.dependencies] diff --git a/integration-tests/smoke/capabilities/workflow_test.go b/integration-tests/smoke/capabilities/workflow_test.go index 2b984443971..eb54875eafe 100644 --- a/integration-tests/smoke/capabilities/workflow_test.go +++ b/integration-tests/smoke/capabilities/workflow_test.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/go-yaml/yaml" "github.com/google/go-github/v41/github" + "github.com/google/uuid" "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" @@ -41,12 +42,14 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/jd" ns "github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/seth" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/integration-tests/actions" pkgworkflows "github.com/smartcontractkit/chainlink-common/pkg/workflows" + jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/feeds_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/workflow/generated/workflow_registry_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -1026,6 +1029,25 @@ func configureNodes(t *testing.T, don *devenv.DON, in *WorkflowTestConfig, bc *b return nodeset, nodeClients } +func reinitialiseJDClient(t *testing.T, ctfEnv *deployment.Environment, jdOutput *jd.Output, nodeOutput *ns.Output) deployment.Environment { + nodeInfo, err := getNodeInfo(nodeOutput, 1) + require.NoError(t, err, "failed to get node info") + + jdConfig := devenv.JDConfig{ + GRPC: jdOutput.HostGRPCUrl, + WSRPC: jdOutput.DockerWSRPCUrl, + Creds: insecure.NewCredentials(), + NodeInfo: nodeInfo, + } + + offChain, err := devenv.NewJDClient(context.Background(), jdConfig) + require.NoError(t, err, "failed to create JD client") + + ctfEnv.Offchain = offChain + + return *ctfEnv +} + func mustSafeUint64(input int64) uint64 { if input < 0 { panic(fmt.Errorf("int64 %d is below uint64 min value", input)) @@ -1033,22 +1055,23 @@ func mustSafeUint64(input int64) uint64 { return uint64(input) } -func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don *devenv.DON, bc *blockchain.Output, keystoneContractSet keystone_changeset.ContractSet, donID uint32) { +func createNodeJobsWithJd(t *testing.T, ctfEnv *deployment.Environment, don *devenv.DON, bc *blockchain.Output, keystoneContractSet keystone_changeset.ContractSet) { // if there's only one OCR3 contract in the set, we can use `nil` as the address to get its instance ocr3Contract, err := keystoneContractSet.GetOCR3Contract(nil) require.NoError(t, err, "failed to get OCR3 contract address") ocr3CapabilityAddress := ocr3Contract.Address().Hex() - bootstrapNodePeerId, err := nodeToP2PID(don.Nodes[0], keyExtractingTransformFn) - require.NoError(t, err, "failed to get bootstrap node peer ID") - chainIDInt, err := strconv.Atoi(bc.ChainID) require.NoError(t, err, "failed to convert chain ID to int") chainIDUint64 := mustSafeUint64(int64(chainIDInt)) - // Create gateway and bootstrap (ocr3) jobs for the bootstrap node - bootstrapNode := nodeClients[0] + bootstrapNodePeerId, err := nodeToP2PID(don.Nodes[0], keyExtractingTransformFn) + require.NoError(t, err, "failed to get bootstrap node peer ID") + + jobCount := 2 + (len(don.Nodes)-1)*3 + errCh := make(chan error, jobCount) + var wg sync.WaitGroup wg.Add(1) go func() { @@ -1057,49 +1080,52 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don * bootstrapJobSpec := fmt.Sprintf(` type = "bootstrap" schemaVersion = 1 + externalJobID = "%s" name = "Botostrap" contractID = "%s" contractConfigTrackerPollInterval = "1s" contractConfigConfirmations = 1 relay = "evm" - [relayConfig] chainID = %s providerType = "ocr3-capability" - `, + `, uuid.NewString(), ocr3CapabilityAddress, - bc.ChainID, - ) - r, _, bootErr := bootstrapNode.CreateJobRaw(bootstrapJobSpec) - assert.NoError(t, bootErr, "failed to create bootstrap job for the bootstrap node") - assert.Empty(t, r.Errors, "failed to create bootstrap job for the bootstrap node") + bc.ChainID) + + bootstrapJobRequest := &jobv1.ProposeJobRequest{ + NodeId: don.Nodes[0].NodeID, + Spec: bootstrapJobSpec, + } + + _, bootErr := ctfEnv.Offchain.ProposeJob(context.Background(), bootstrapJobRequest) + if bootErr != nil { + errCh <- errors.Wrapf(bootErr, "failed to propose bootstrap job") + return + } gatewayJobSpec := fmt.Sprintf(` type = "gateway" schemaVersion = 1 + externalJobID = "%s" name = "Gateway" forwardingAllowed = false - [gatewayConfig.ConnectionManagerConfig] AuthChallengeLen = 10 AuthGatewayId = "por_gateway" AuthTimestampToleranceSec = 5 HeartbeatIntervalSec = 20 - [[gatewayConfig.Dons]] - DonId = "%s" + DonId = "1" F = 1 HandlerName = "web-api-capabilities" - [gatewayConfig.Dons.HandlerConfig] MaxAllowedMessageAgeSec = 1_000 - [gatewayConfig.Dons.HandlerConfig.NodeRateLimiter] GlobalBurst = 10 GlobalRPS = 50 PerSenderBurst = 10 PerSenderRPS = 10 - [[gatewayConfig.Dons.Members]] Address = "%s" Name = "Workflow Node 1" @@ -1112,7 +1138,6 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don * [[gatewayConfig.Dons.Members]] Address = "%s" Name = "Workflow Node 4" - [gatewayConfig.NodeServerConfig] HandshakeTimeoutMillis = 1_000 MaxRequestBytes = 100_000 @@ -1121,7 +1146,6 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don * ReadTimeoutMillis = 1_000 RequestTimeoutMillis = 10_000 WriteTimeoutMillis = 1_000 - [gatewayConfig.UserServerConfig] ContentTypeHeader = "application/jsonrpc" MaxRequestBytes = 100_000 @@ -1130,11 +1154,10 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don * ReadTimeoutMillis = 1_000 RequestTimeoutMillis = 10_000 WriteTimeoutMillis = 1_000 - [gatewayConfig.HTTPClientConfig] MaxResponseBytes = 100_000_000 `, - strconv.FormatUint(uint64(donID), 10), + uuid.NewString(), // ETH keys of the workflow nodes don.Nodes[1].AccountAddr[chainIDUint64], don.Nodes[2].AccountAddr[chainIDUint64], @@ -1142,13 +1165,19 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don * don.Nodes[4].AccountAddr[chainIDUint64], ) - r, _, gatewayErr := bootstrapNode.CreateJobRaw(gatewayJobSpec) - assert.NoError(t, gatewayErr, "failed to create gateway job for the bootstrap node") - assert.Empty(t, r.Errors, "failed to create gateway job for the bootstrap node") + gatewayJobRequest := &jobv1.ProposeJobRequest{ + NodeId: don.Nodes[0].NodeID, + Spec: gatewayJobSpec, + } + + _, gateErr := ctfEnv.Offchain.ProposeJob(context.Background(), gatewayJobRequest) + if gateErr != nil { + errCh <- errors.Wrapf(gateErr, "failed to propose gateway job for the bootstrap node") + } }() // for each capability that's required by the workflow, create a job for workflow each node - for i, nodeClient := range nodeClients { + for i, node := range don.Nodes { // First node is a bootstrap node, so we skip it if i == 0 { continue @@ -1159,24 +1188,35 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don * defer wg.Done() // since we are using a capability that is not bundled-in, we need to copy it to the Docker container // and point the job to the copied binary + + // failed to propose job. err: rpc error: code = Internal desc = failed to propose job to node: failed to generate a job based on spec: unknown job type: standardcapabilities cronJobSpec := fmt.Sprintf(` type = "standardcapabilities" schemaVersion = 1 + externalJobID = "%s" name = "cron-capabilities" forwardingAllowed = false command = "/home/capabilities/%s" config = "" `, - cronCapabilityAssetFile, - ) + uuid.NewString(), + cronCapabilityAssetFile) + + cronJobRequest := &jobv1.ProposeJobRequest{ + NodeId: node.NodeID, + Spec: cronJobSpec, + } - response, _, errCron := nodeClient.CreateJobRaw(cronJobSpec) - assert.NoError(t, errCron, "failed to create cron job") - assert.Empty(t, response.Errors, "failed to create cron job") + _, cronErr := ctfEnv.Offchain.ProposeJob(context.Background(), cronJobRequest) + if cronErr != nil { + errCh <- errors.Wrapf(cronErr, "failed to propose cron job for node %s", node.NodeID) + return + } - computeJobSpec := ` + computeJobSpec := fmt.Sprintf(` type = "standardcapabilities" schemaVersion = 1 + externalJobID = "%s" name = "compute-capabilities" forwardingAllowed = false command = "__builtin_custom-compute-action" @@ -1188,15 +1228,24 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don * perSenderRPS = 1.0 perSenderBurst = 5 """ - ` + `, + uuid.NewString()) - response, _, errCompute := nodeClient.CreateJobRaw(computeJobSpec) - assert.NoError(t, errCompute, "failed to create compute job") - assert.Empty(t, response.Errors, "failed to create compute job") + computeJobRequest := &jobv1.ProposeJobRequest{ + NodeId: node.NodeID, + Spec: computeJobSpec, + } + + _, compErr := ctfEnv.Offchain.ProposeJob(context.Background(), computeJobRequest) + if compErr != nil { + errCh <- errors.Wrapf(compErr, "failed to propose compute job for node %s", node.NodeID) + return + } consensusJobSpec := fmt.Sprintf(` type = "offchainreporting2" schemaVersion = 1 + externalJobID = "%s" name = "Keystone OCR3 Consensus Capability" contractID = "%s" ocrKeyBundleID = "%s" @@ -1206,37 +1255,52 @@ func createNodeJobs(t *testing.T, nodeClients []*clclient.ChainlinkClient, don * relay = "evm" pluginType = "plugin" transmitterID = "%s" - [relayConfig] chainID = "%s" - [pluginConfig] command = "/usr/local/bin/chainlink-ocr3-capability" ocrVersion = 3 pluginName = "ocr-capability" providerType = "ocr3-capability" telemetryType = "plugin" - [onchainSigningStrategy] strategyName = 'multi-chain' [onchainSigningStrategy.config] evm = "%s" `, + uuid.NewString(), ocr3CapabilityAddress, - don.Nodes[i].Ocr2KeyBundleID, + node.Ocr2KeyBundleID, bootstrapNodePeerId, "node0:5001", - don.Nodes[i].AccountAddr[chainIDUint64], + node.AccountAddr[chainIDUint64], bc.ChainID, - don.Nodes[i].Ocr2KeyBundleID, + node.Ocr2KeyBundleID, ) - fmt.Println("consensusJobSpec", consensusJobSpec) - response, _, errCons := nodeClient.CreateJobRaw(consensusJobSpec) - assert.NoError(t, errCons, "failed to create consensus job") - assert.Empty(t, response.Errors, "failed to create consensus job") + + consensusJobRequest := &jobv1.ProposeJobRequest{ + NodeId: node.NodeID, + Spec: consensusJobSpec, + } + + _, consErr := ctfEnv.Offchain.ProposeJob(context.Background(), consensusJobRequest) + if consErr != nil { + errCh <- errors.Wrapf(consErr, "failed to propose consensus job for node %s ", node.NodeID) + } }() } wg.Wait() + + close(errCh) + + errFound := false + for err := range errCh { + errFound = true + //nolint:testifylint // we want to assert here to catch all errors + assert.NoError(t, err, "job creation/acception failed") + } + + require.False(t, errFound, "failed to create at least one job") } func noOpTransformFn(value string) string { @@ -1697,9 +1761,11 @@ func TestKeystoneWithOCR3Workflow(t *testing.T) { // Register the workflow (either via CRE CLI or by calling the workflow registry directly) registerWorkflow(t, in, sc, keystoneContractSet.CapabilitiesRegistry.Address(), workflowRegistryAddr, feedsConsumerAddress, in.WorkflowConfig.DonID, chainSelector, in.WorkflowConfig.WorkflowName, pkey, bc.Nodes[0].HostHTTPUrl) - // Create OCR3 and capability jobs for each node without JD - ns, nodeClients := configureNodes(t, don, in, bc, keystoneContractSet.CapabilitiesRegistry.Address(), workflowRegistryAddr, keystoneContractSet.Forwarder.Address()) - createNodeJobs(t, nodeClients, don, bc, keystoneContractSet, in.WorkflowConfig.DonID) + // Create OCR3 and capability jobs for each node JD + ns, _ := configureNodes(t, don, in, bc, keystoneContractSet.CapabilitiesRegistry.Address(), workflowRegistryAddr, keystoneContractSet.Forwarder.Address()) + // JD client needs to be reinitialised after restarting nodes + ctfEnv = ptr.Ptr(reinitialiseJDClient(t, ctfEnv, jdOutput, nodeOutput)) + createNodeJobsWithJd(t, ctfEnv, don, bc, keystoneContractSet) // Log extra information that might help debugging t.Cleanup(func() { @@ -1738,7 +1804,8 @@ func TestKeystoneWithOCR3Workflow(t *testing.T) { for { select { case <-ctx.Done(): - t.Fatalf("feed did not update, timeout after %s", timeout) + testLogger.Error().Msgf("feed did not update, timeout after %s", timeout) + t.FailNow() case <-time.After(10 * time.Second): elapsed := time.Since(startTime).Round(time.Second) price, _, err := feedsConsumerInstance.GetPrice( From f68893b98333169d2df1f95ba727ae2f070c9994 Mon Sep 17 00:00:00 2001 From: Makram Date: Mon, 3 Feb 2025 21:33:57 +0200 Subject: [PATCH 42/43] [CCIP-5108] integration-tests/smoke/ccip: extract msging test case into pkg (#16168) * integration-tests/smoke/ccip: extract msging test case into pkg Extract the messaging test case structs and related functions to a separate package so that it can also be used from chainlink-deployments. * simplify testcase * goimports --- .../testhelpers/messagingtest/helpers.go | 202 ++++++++++++++ .../smoke/ccip/ccip_messaging_test.go | 258 +++++------------- 2 files changed, 271 insertions(+), 189 deletions(-) create mode 100644 deployment/ccip/changeset/testhelpers/messagingtest/helpers.go diff --git a/deployment/ccip/changeset/testhelpers/messagingtest/helpers.go b/deployment/ccip/changeset/testhelpers/messagingtest/helpers.go new file mode 100644 index 00000000000..36b03e576de --- /dev/null +++ b/deployment/ccip/changeset/testhelpers/messagingtest/helpers.go @@ -0,0 +1,202 @@ +package messagingtest + +import ( + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + chain_selectors "github.com/smartcontractkit/chain-selectors" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" +) + +// Use this when testhelpers.DeployedEnv is available (usually in ephemeral test environments). +func NewTestSetupWithDeployedEnv( + t *testing.T, + depEnv testhelpers.DeployedEnv, + onchainState changeset.CCIPOnChainState, + sourceChain, + destChain uint64, + sender []byte, + testRouter, + validateResp bool, +) TestSetup { + return TestSetup{ + T: t, + Sender: sender, + Env: depEnv.Env, + DeployedEnv: depEnv, + OnchainState: onchainState, + SourceChain: sourceChain, + DestChain: destChain, + TestRouter: testRouter, + ValidateResp: validateResp, + } +} + +// Use this when testhelpers.DeployedEnv is not available (usually in long-running test environments like staging). +func NewTestSetup( + t *testing.T, + env deployment.Environment, + onchainState changeset.CCIPOnChainState, + sourceChain, + destChain uint64, + sender []byte, + testRouter, + validateResp bool, +) TestSetup { + return TestSetup{ + T: t, + Sender: sender, + Env: env, + // no DeployedEnv + OnchainState: onchainState, + SourceChain: sourceChain, + DestChain: destChain, + TestRouter: testRouter, + ValidateResp: validateResp, + } +} + +type TestSetup struct { + T *testing.T + Sender []byte + Env deployment.Environment + DeployedEnv testhelpers.DeployedEnv + OnchainState changeset.CCIPOnChainState + SourceChain uint64 + DestChain uint64 + TestRouter bool + ValidateResp bool +} + +type TestCase struct { + TestSetup + Replayed bool + Nonce uint64 + Receiver common.Address + MsgData []byte + ExtraArgs []byte + ExpectedExecutionState int + ExtraAssertions []func(t *testing.T) +} + +type TestCaseOutput struct { + Replayed bool + Nonce uint64 + MsgSentEvent *onramp.OnRampCCIPMessageSent +} + +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 + + testhelpers.ReplayLogs(t, e.Env.Offchain, replayBlocks) +} + +func getLatestNonce(tc TestCase) uint64 { + family, err := chain_selectors.GetSelectorFamily(tc.DestChain) + require.NoError(tc.T, err) + + var latestNonce uint64 + switch family { + case chain_selectors.FamilyEVM: + latestNonce, err = tc.OnchainState.Chains[tc.DestChain].NonceManager.GetInboundNonce(&bind.CallOpts{ + Context: tests.Context(tc.T), + }, tc.SourceChain, tc.Sender) + require.NoError(tc.T, err) + case chain_selectors.FamilySolana: + // var nonceCounterAccount ccip_router.Nonce + // err = common.GetAccountDataBorshInto(ctx, solanaGoClient, nonceEvmPDA, config.DefaultCommitment, &nonceCounterAccount) + // require.NoError(t, err, "failed to get account info") + // require.Equal(t, uint64(1), nonceCounterAccount.Counter) + } + return latestNonce +} + +// Run runs a messaging test case. +func Run(tc TestCase) (out TestCaseOutput) { + // check latest nonce + latestNonce := getLatestNonce(tc) + require.Equal(tc.T, tc.Nonce, latestNonce) + + startBlocks := make(map[uint64]*uint64) + msgSentEvent := testhelpers.TestSendRequest( + tc.T, + tc.Env, + tc.OnchainState, + tc.SourceChain, + tc.DestChain, + tc.TestRouter, + router.ClientEVM2AnyMessage{ + Receiver: common.LeftPadBytes(tc.Receiver.Bytes(), 32), + Data: tc.MsgData, + TokenAmounts: nil, + FeeToken: common.HexToAddress("0x0"), + ExtraArgs: tc.ExtraArgs, + }) + expectedSeqNum := map[testhelpers.SourceDestPair]uint64{ + { + SourceChainSelector: tc.SourceChain, + DestChainSelector: tc.DestChain, + }: msgSentEvent.SequenceNumber, + } + expectedSeqNumExec := map[testhelpers.SourceDestPair][]uint64{ + { + SourceChainSelector: tc.SourceChain, + DestChainSelector: tc.DestChain, + }: {msgSentEvent.SequenceNumber}, + } + out.MsgSentEvent = msgSentEvent + + // hack + if !tc.Replayed { + require.NotNil(tc.T, tc.DeployedEnv) + sleepAndReplay(tc.T, tc.DeployedEnv, tc.SourceChain, tc.DestChain) + out.Replayed = true + } + + if tc.ValidateResp { + testhelpers.ConfirmCommitForAllWithExpectedSeqNums(tc.T, tc.Env, tc.OnchainState, expectedSeqNum, startBlocks) + execStates := testhelpers.ConfirmExecWithSeqNrsForAll(tc.T, tc.Env, tc.OnchainState, expectedSeqNumExec, startBlocks) + + require.Equalf( + tc.T, + tc.ExpectedExecutionState, + execStates[testhelpers.SourceDestPair{ + SourceChainSelector: tc.SourceChain, + DestChainSelector: tc.DestChain, + }][msgSentEvent.SequenceNumber], + "wrong execution state for seq nr %d, expected %d, got %d", + msgSentEvent.SequenceNumber, + tc.ExpectedExecutionState, + execStates[testhelpers.SourceDestPair{ + SourceChainSelector: tc.SourceChain, + DestChainSelector: tc.DestChain, + }][msgSentEvent.SequenceNumber], + ) + + // check the sender latestNonce on the dest, should be incremented + latestNonce = getLatestNonce(tc) + require.Equal(tc.T, tc.Nonce+1, latestNonce) + out.Nonce = latestNonce + tc.T.Logf("confirmed nonce bump for sender %x, latestNonce %d", tc.Sender, latestNonce) + + for _, assertion := range tc.ExtraAssertions { + assertion(tc.T) + } + } else { + tc.T.Logf("skipping validation of sent message") + } + + return +} diff --git a/integration-tests/smoke/ccip/ccip_messaging_test.go b/integration-tests/smoke/ccip/ccip_messaging_test.go index 69900b29322..eb9b4bfd847 100644 --- a/integration-tests/smoke/ccip/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip/ccip_messaging_test.go @@ -5,48 +5,23 @@ import ( "fmt" "math/big" "testing" - "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" - chain_selectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-common/pkg/hashutil" "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" + mt "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers/messagingtest" 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" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" ) -type testCaseSetup struct { - t *testing.T - sender []byte - deployedEnv testhelpers.DeployedEnv - onchainState changeset.CCIPOnChainState - sourceChain, destChain uint64 -} - -type messagingTestCase struct { - testCaseSetup - replayed bool - nonce uint64 -} - -type messagingTestCaseOutput struct { - replayed bool - nonce uint64 - msgSentEvent *onramp.OnRampCCIPMessageSent -} - func Test_CCIPMessaging(t *testing.T) { // Setup 2 chains and a single lane. ctx := testhelpers.Context(t) @@ -72,65 +47,70 @@ func Test_CCIPMessaging(t *testing.T) { replayed bool nonce uint64 sender = common.LeftPadBytes(e.Env.Chains[sourceChain].DeployerKey.From.Bytes(), 32) - out messagingTestCaseOutput - setup = testCaseSetup{ - t: t, - sender: sender, - deployedEnv: e, - onchainState: state, - sourceChain: sourceChain, - destChain: destChain, - } + out mt.TestCaseOutput + setup = mt.NewTestSetupWithDeployedEnv( + t, + e, + state, + sourceChain, + destChain, + sender, + false, // testRouter + true, // validateResp + ) ) t.Run("data message to eoa", func(t *testing.T) { - out = runMessagingTestCase(messagingTestCase{ - testCaseSetup: setup, - replayed: replayed, - nonce: nonce, - }, - common.HexToAddress("0xdead"), - []byte("hello eoa"), - nil, // default extraArgs - testhelpers.EXECUTION_STATE_SUCCESS, // success because offRamp won't call an EOA + out = mt.Run( + mt.TestCase{ + TestSetup: setup, + Replayed: replayed, + Nonce: nonce, + Receiver: common.HexToAddress("0xdead"), + MsgData: []byte("hello eoa"), + ExtraArgs: nil, // default extraArgs + ExpectedExecutionState: testhelpers.EXECUTION_STATE_SUCCESS, // success because offRamp won't call an EOA + }, ) }) t.Run("message to contract not implementing CCIPReceiver", func(t *testing.T) { - out = runMessagingTestCase( - messagingTestCase{ - testCaseSetup: setup, - replayed: out.replayed, - nonce: out.nonce, + out = mt.Run( + mt.TestCase{ + TestSetup: setup, + Replayed: out.Replayed, + Nonce: out.Nonce, + Receiver: state.Chains[destChain].FeeQuoter.Address(), + MsgData: []byte("hello FeeQuoter"), + ExtraArgs: nil, // default extraArgs + ExpectedExecutionState: testhelpers.EXECUTION_STATE_SUCCESS, // success because offRamp won't call a contract not implementing CCIPReceiver }, - state.Chains[destChain].FeeQuoter.Address(), - []byte("hello FeeQuoter"), - nil, // default extraArgs - testhelpers.EXECUTION_STATE_SUCCESS, // success because offRamp won't call a contract not implementing CCIPReceiver ) }) t.Run("message to contract implementing CCIPReceiver", func(t *testing.T) { latestHead, err := e.Env.Chains[destChain].Client.HeaderByNumber(ctx, nil) require.NoError(t, err) - out = runMessagingTestCase( - messagingTestCase{ - testCaseSetup: setup, - replayed: out.replayed, - nonce: out.nonce, - }, - state.Chains[destChain].Receiver.Address(), - []byte("hello CCIPReceiver"), - nil, // default extraArgs - testhelpers.EXECUTION_STATE_SUCCESS, - func(t *testing.T) { - iter, err := state.Chains[destChain].Receiver.FilterMessageReceived(&bind.FilterOpts{ - Context: ctx, - Start: latestHead.Number.Uint64(), - }) - require.NoError(t, err) - require.True(t, iter.Next()) - // MessageReceived doesn't emit the data unfortunately, so can't check that. + out = mt.Run( + mt.TestCase{ + TestSetup: setup, + Replayed: out.Replayed, + Nonce: out.Nonce, + Receiver: state.Chains[destChain].Receiver.Address(), + MsgData: []byte("hello CCIPReceiver"), + ExtraArgs: nil, // default extraArgs + ExpectedExecutionState: testhelpers.EXECUTION_STATE_SUCCESS, + ExtraAssertions: []func(t *testing.T){ + func(t *testing.T) { + iter, err := state.Chains[destChain].Receiver.FilterMessageReceived(&bind.FilterOpts{ + Context: ctx, + Start: latestHead.Number.Uint64(), + }) + require.NoError(t, err) + require.True(t, iter.Next()) + // MessageReceived doesn't emit the data unfortunately, so can't check that. + }, + }, }, ) }) @@ -138,22 +118,22 @@ func Test_CCIPMessaging(t *testing.T) { t.Run("message to contract implementing CCIPReceiver with low exec gas", func(t *testing.T) { latestHead, err := e.Env.Chains[destChain].Client.HeaderByNumber(ctx, nil) require.NoError(t, err) - out = runMessagingTestCase( - messagingTestCase{ - testCaseSetup: setup, - replayed: out.replayed, - nonce: out.nonce, + out = mt.Run( + mt.TestCase{ + TestSetup: setup, + Replayed: out.Replayed, + Nonce: out.Nonce, + Receiver: state.Chains[destChain].Receiver.Address(), + MsgData: []byte("hello CCIPReceiver with low exec gas"), + ExtraArgs: testhelpers.MakeEVMExtraArgsV2(1, false), // 1 gas is too low. + ExpectedExecutionState: testhelpers.EXECUTION_STATE_FAILURE, // state would be failed onchain due to low gas }, - state.Chains[destChain].Receiver.Address(), - []byte("hello CCIPReceiver with low exec 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) t.Logf("successfully manually executed message %x", - out.msgSentEvent.Message.Header.MessageId) + out.MsgSentEvent.Message.Header.MessageId) }) } @@ -163,7 +143,7 @@ func manuallyExecute( startBlock uint64, state changeset.CCIPOnChainState, destChain uint64, - out messagingTestCaseOutput, + out mt.TestCaseOutput, sourceChain uint64, e testhelpers.DeployedEnv, sender []byte, @@ -172,7 +152,7 @@ func manuallyExecute( ctx, t, state.Chains[destChain].OffRamp, - out.msgSentEvent.SequenceNumber, + out.MsgSentEvent.SequenceNumber, startBlock, ) messageHash := getMessageHash( @@ -180,8 +160,8 @@ func manuallyExecute( t, state.Chains[destChain].OffRamp, sourceChain, - out.msgSentEvent.SequenceNumber, - out.msgSentEvent.Message.Header.MessageId, + out.MsgSentEvent.SequenceNumber, + out.MsgSentEvent.Message.Header.MessageId, startBlock, ) tree, err := merklemulti.NewTree(hashutil.NewKeccak(), [][32]byte{messageHash}) @@ -198,11 +178,11 @@ func manuallyExecute( Messages: []offramp.InternalAny2EVMRampMessage{ { Header: offramp.InternalRampMessageHeader{ - MessageId: out.msgSentEvent.Message.Header.MessageId, + MessageId: out.MsgSentEvent.Message.Header.MessageId, SourceChainSelector: sourceChain, DestChainSelector: destChain, - SequenceNumber: out.msgSentEvent.SequenceNumber, - Nonce: out.msgSentEvent.Message.Header.Nonce, + SequenceNumber: out.MsgSentEvent.SequenceNumber, + Nonce: out.MsgSentEvent.Message.Header.Nonce, }, Sender: sender, Data: []byte("hello CCIPReceiver with low exec gas"), @@ -230,7 +210,7 @@ func manuallyExecute( _, err = deployment.ConfirmIfNoError(e.Env.Chains[destChain], tx, err) require.NoError(t, err, "failed to send/confirm manuallyExecute tx") - newExecutionState, err := state.Chains[destChain].OffRamp.GetExecutionState(&bind.CallOpts{Context: ctx}, sourceChain, out.msgSentEvent.SequenceNumber) + newExecutionState, err := state.Chains[destChain].OffRamp.GetExecutionState(&bind.CallOpts{Context: ctx}, sourceChain, out.MsgSentEvent.SequenceNumber) require.NoError(t, err) require.Equal(t, uint8(testhelpers.EXECUTION_STATE_SUCCESS), newExecutionState) } @@ -288,106 +268,6 @@ func getMessageHash( return iter.Event.MessageHash } -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 - testhelpers.ReplayLogs(t, e.Env.Offchain, replayBlocks) -} - -func getLatestNonce(tc messagingTestCase) uint64 { - family, err := chain_selectors.GetSelectorFamily(tc.destChain) - require.NoError(tc.t, err) - - var latestNonce uint64 - switch family { - case chain_selectors.FamilyEVM: - latestNonce, err = tc.onchainState.Chains[tc.destChain].NonceManager.GetInboundNonce(&bind.CallOpts{ - Context: tests.Context(tc.t), - }, tc.sourceChain, tc.sender) - require.NoError(tc.t, err) - case chain_selectors.FamilySolana: - // var nonceCounterAccount ccip_router.Nonce - // err = common.GetAccountDataBorshInto(ctx, solanaGoClient, nonceEvmPDA, config.DefaultCommitment, &nonceCounterAccount) - // require.NoError(t, err, "failed to get account info") - // require.Equal(t, uint64(1), nonceCounterAccount.Counter) - } - return latestNonce -} - -func runMessagingTestCase( - tc messagingTestCase, - receiver common.Address, - msgData []byte, - extraArgs []byte, - expectedExecutionState int, - extraAssertions ...func(t *testing.T), -) (out messagingTestCaseOutput) { - // check latest nonce - latestNonce := getLatestNonce(tc) - require.Equal(tc.t, tc.nonce, latestNonce) - - startBlocks := make(map[uint64]*uint64) - 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[testhelpers.SourceDestPair]uint64{ - { - SourceChainSelector: tc.sourceChain, - DestChainSelector: tc.destChain, - }: msgSentEvent.SequenceNumber, - } - expectedSeqNumExec := map[testhelpers.SourceDestPair][]uint64{ - { - SourceChainSelector: tc.sourceChain, - DestChainSelector: tc.destChain, - }: {msgSentEvent.SequenceNumber}, - } - out.msgSentEvent = msgSentEvent - - // hack - if !tc.replayed { - sleepAndReplay(tc.t, tc.deployedEnv, tc.sourceChain, tc.destChain) - out.replayed = true - } - - 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[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[testhelpers.SourceDestPair{ - SourceChainSelector: tc.sourceChain, - DestChainSelector: tc.destChain, - }][msgSentEvent.SequenceNumber], - ) - - // check the sender latestNonce on the dest, should be incremented - latestNonce = getLatestNonce(tc) - require.Equal(tc.t, tc.nonce+1, latestNonce) - out.nonce = latestNonce - tc.t.Logf("confirmed nonce bump for sender %x, latestNonce %d", tc.sender, latestNonce) - - for _, assertion := range extraAssertions { - assertion(tc.t) - } - - return -} - // boolsToBitFlags transforms a list of boolean flags to a *big.Int encoded number. func boolsToBitFlags(bools []bool) *big.Int { encodedFlags := big.NewInt(0) From aa1cb03e68b81401f2fb95de8c7875fc2f13cce3 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 3 Feb 2025 14:08:38 -0600 Subject: [PATCH 43/43] bump framework; simplify keystore (#16194) --- common/txmgr/types/mocks/key_store.go | 68 +++++++++++++-------------- core/chains/evm/txmgr/models.go | 2 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- deployment/go.mod | 2 +- deployment/go.sum | 4 +- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 +- 12 files changed, 50 insertions(+), 50 deletions(-) diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index 4d9508919f3..050128eaa54 100644 --- a/common/txmgr/types/mocks/key_store.go +++ b/common/txmgr/types/mocks/key_store.go @@ -11,20 +11,20 @@ import ( ) // KeyStore is an autogenerated mock type for the KeyStore type -type KeyStore[ADDR chains.Hashable, CHAIN_ID chains.ID, SEQ chains.Sequence] struct { +type KeyStore[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { mock.Mock } -type KeyStore_Expecter[ADDR chains.Hashable, CHAIN_ID chains.ID, SEQ chains.Sequence] struct { +type KeyStore_Expecter[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { mock *mock.Mock } -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EXPECT() *KeyStore_Expecter[ADDR, CHAIN_ID, SEQ] { - return &KeyStore_Expecter[ADDR, CHAIN_ID, SEQ]{mock: &_m.Mock} +func (_m *KeyStore[ADDR, CHAIN_ID]) EXPECT() *KeyStore_Expecter[ADDR, CHAIN_ID] { + return &KeyStore_Expecter[ADDR, CHAIN_ID]{mock: &_m.Mock} } // CheckEnabled provides a mock function with given fields: ctx, address, chainID -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(ctx context.Context, address ADDR, chainID CHAIN_ID) error { +func (_m *KeyStore[ADDR, CHAIN_ID]) CheckEnabled(ctx context.Context, address ADDR, chainID CHAIN_ID) error { ret := _m.Called(ctx, address, chainID) if len(ret) == 0 { @@ -42,7 +42,7 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(ctx context.Context, addre } // KeyStore_CheckEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckEnabled' -type KeyStore_CheckEnabled_Call[ADDR chains.Hashable, CHAIN_ID chains.ID, SEQ chains.Sequence] struct { +type KeyStore_CheckEnabled_Call[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { *mock.Call } @@ -50,30 +50,30 @@ type KeyStore_CheckEnabled_Call[ADDR chains.Hashable, CHAIN_ID chains.ID, SEQ ch // - ctx context.Context // - address ADDR // - chainID CHAIN_ID -func (_e *KeyStore_Expecter[ADDR, CHAIN_ID, SEQ]) CheckEnabled(ctx interface{}, address interface{}, chainID interface{}) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID, SEQ] { - return &KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID, SEQ]{Call: _e.mock.On("CheckEnabled", ctx, address, chainID)} +func (_e *KeyStore_Expecter[ADDR, CHAIN_ID]) CheckEnabled(ctx interface{}, address interface{}, chainID interface{}) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID] { + return &KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID]{Call: _e.mock.On("CheckEnabled", ctx, address, chainID)} } -func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID, SEQ]) Run(run func(ctx context.Context, address ADDR, chainID CHAIN_ID)) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID]) Run(run func(ctx context.Context, address ADDR, chainID CHAIN_ID)) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID] { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(ADDR), args[2].(CHAIN_ID)) }) return _c } -func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID, SEQ]) Return(_a0 error) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID]) Return(_a0 error) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID] { _c.Call.Return(_a0) return _c } -func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID, SEQ]) RunAndReturn(run func(context.Context, ADDR, CHAIN_ID) error) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID]) RunAndReturn(run func(context.Context, ADDR, CHAIN_ID) error) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID] { _c.Call.Return(run) return _c } -// EnabledAddressesForChain provides a mock function with given fields: ctx, chainId -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(ctx context.Context, chainId CHAIN_ID) ([]ADDR, error) { - ret := _m.Called(ctx, chainId) +// EnabledAddressesForChain provides a mock function with given fields: ctx, chainID +func (_m *KeyStore[ADDR, CHAIN_ID]) EnabledAddressesForChain(ctx context.Context, chainID CHAIN_ID) ([]ADDR, error) { + ret := _m.Called(ctx, chainID) if len(ret) == 0 { panic("no return value specified for EnabledAddressesForChain") @@ -82,10 +82,10 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(ctx context.Co var r0 []ADDR var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]ADDR, error)); ok { - return rf(ctx, chainId) + return rf(ctx, chainID) } if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) []ADDR); ok { - r0 = rf(ctx, chainId) + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]ADDR) @@ -93,7 +93,7 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(ctx context.Co } if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { - r1 = rf(ctx, chainId) + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -102,36 +102,36 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(ctx context.Co } // KeyStore_EnabledAddressesForChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnabledAddressesForChain' -type KeyStore_EnabledAddressesForChain_Call[ADDR chains.Hashable, CHAIN_ID chains.ID, SEQ chains.Sequence] struct { +type KeyStore_EnabledAddressesForChain_Call[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { *mock.Call } // EnabledAddressesForChain is a helper method to define mock.On call // - ctx context.Context -// - chainId CHAIN_ID -func (_e *KeyStore_Expecter[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(ctx interface{}, chainId interface{}) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID, SEQ] { - return &KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID, SEQ]{Call: _e.mock.On("EnabledAddressesForChain", ctx, chainId)} +// - chainID CHAIN_ID +func (_e *KeyStore_Expecter[ADDR, CHAIN_ID]) EnabledAddressesForChain(ctx interface{}, chainID interface{}) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID] { + return &KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID]{Call: _e.mock.On("EnabledAddressesForChain", ctx, chainID)} } -func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID, SEQ]) Run(run func(ctx context.Context, chainId CHAIN_ID)) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID]) Run(run func(ctx context.Context, chainID CHAIN_ID)) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID] { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(CHAIN_ID)) }) return _c } -func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID, SEQ]) Return(_a0 []ADDR, _a1 error) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID]) Return(_a0 []ADDR, _a1 error) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID] { _c.Call.Return(_a0, _a1) return _c } -func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID, SEQ]) RunAndReturn(run func(context.Context, CHAIN_ID) ([]ADDR, error)) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID]) RunAndReturn(run func(context.Context, CHAIN_ID) ([]ADDR, error)) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID] { _c.Call.Return(run) return _c } // SubscribeToKeyChanges provides a mock function with given fields: ctx -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges(ctx context.Context) (chan struct{}, func()) { +func (_m *KeyStore[ADDR, CHAIN_ID]) SubscribeToKeyChanges(ctx context.Context) (chan struct{}, func()) { ret := _m.Called(ctx) if len(ret) == 0 { @@ -163,40 +163,40 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges(ctx context.Conte } // KeyStore_SubscribeToKeyChanges_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeToKeyChanges' -type KeyStore_SubscribeToKeyChanges_Call[ADDR chains.Hashable, CHAIN_ID chains.ID, SEQ chains.Sequence] struct { +type KeyStore_SubscribeToKeyChanges_Call[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { *mock.Call } // SubscribeToKeyChanges is a helper method to define mock.On call // - ctx context.Context -func (_e *KeyStore_Expecter[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges(ctx interface{}) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID, SEQ] { - return &KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID, SEQ]{Call: _e.mock.On("SubscribeToKeyChanges", ctx)} +func (_e *KeyStore_Expecter[ADDR, CHAIN_ID]) SubscribeToKeyChanges(ctx interface{}) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID] { + return &KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID]{Call: _e.mock.On("SubscribeToKeyChanges", ctx)} } -func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID, SEQ]) Run(run func(ctx context.Context)) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID]) Run(run func(ctx context.Context)) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID] { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context)) }) return _c } -func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID, SEQ]) Return(ch chan struct{}, unsub func()) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID]) Return(ch chan struct{}, unsub func()) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID] { _c.Call.Return(ch, unsub) return _c } -func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID, SEQ]) RunAndReturn(run func(context.Context) (chan struct{}, func())) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID, SEQ] { +func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID]) RunAndReturn(run func(context.Context) (chan struct{}, func())) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID] { _c.Call.Return(run) return _c } // NewKeyStore creates a new instance of KeyStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. -func NewKeyStore[ADDR chains.Hashable, CHAIN_ID chains.ID, SEQ chains.Sequence](t interface { +func NewKeyStore[ADDR chains.Hashable, CHAIN_ID chains.ID](t interface { mock.TestingT Cleanup(func()) -}) *KeyStore[ADDR, CHAIN_ID, SEQ] { - mock := &KeyStore[ADDR, CHAIN_ID, SEQ]{} +}) *KeyStore[ADDR, CHAIN_ID] { + mock := &KeyStore[ADDR, CHAIN_ID]{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/chains/evm/txmgr/models.go b/core/chains/evm/txmgr/models.go index bf5e7251744..1ebbe54c887 100644 --- a/core/chains/evm/txmgr/models.go +++ b/core/chains/evm/txmgr/models.go @@ -24,7 +24,7 @@ type ( Reaper = txmgr.Reaper[*big.Int] TxStore = txmgrtypes.TxStore[common.Address, *big.Int, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] TransactionStore = txmgrtypes.TransactionStore[common.Address, *big.Int, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] - KeyStore = txmgrtypes.KeyStore[common.Address, *big.Int, evmtypes.Nonce] + KeyStore = txmgrtypes.KeyStore[common.Address, *big.Int] TxAttemptBuilder = txmgrtypes.TxAttemptBuilder[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] NonceTracker = txmgrtypes.SequenceTracker[common.Address, evmtypes.Nonce] TransmitCheckerFactory = txmgr.TransmitCheckerFactory[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] diff --git a/core/scripts/go.mod b/core/scripts/go.mod index decd988fff7..f4047d69eaa 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -319,7 +319,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250128074412-9b02e505b268 // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 014d0110a54..434080fc1e2 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1341,8 +1341,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a h1:fVtn9CDfoGF40FeqGwLvp9belfIw7VT3lgQTctFGP5E= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= diff --git a/deployment/go.mod b/deployment/go.mod index 343e85ea989..f40639f96d8 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -420,7 +420,7 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v0.0.0-20250123084029-58cce9b32112 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20250117224137-afdcdd75070d // indirect diff --git a/deployment/go.sum b/deployment/go.sum index 98a517e366d..3f462b76405 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1406,8 +1406,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a h1:fVtn9CDfoGF40FeqGwLvp9belfIw7VT3lgQTctFGP5E= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= diff --git a/go.mod b/go.mod index 0e2c8dba5a8..f43aa374360 100644 --- a/go.mod +++ b/go.mod @@ -83,7 +83,7 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 github.com/smartcontractkit/chainlink-feeds v0.1.1 - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20250121222331-a7010b4b8ce5 diff --git a/go.sum b/go.sum index 49c7690cf38..2f6a956ab4c 100644 --- a/go.sum +++ b/go.sum @@ -1164,8 +1164,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a h1:fVtn9CDfoGF40FeqGwLvp9belfIw7VT3lgQTctFGP5E= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 h1:ZBat8EBvE2LpSQR9U1gEbRV6PfAkiFdINmQ8nVnXIAQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 45cb3468668..c03c3f521ce 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -439,7 +439,7 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect github.com/smartcontractkit/chainlink-protos/svr v0.0.0-20250123084029-58cce9b32112 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index f9426cd0a10..da675aa46d8 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1434,8 +1434,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a h1:fVtn9CDfoGF40FeqGwLvp9belfIw7VT3lgQTctFGP5E= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 1900e010cb1..e68d5d0c76d 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -423,7 +423,7 @@ require ( github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20250130125138-3df261e09ddc // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.4.0 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index a35db649f9f..858f2b93e28 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1421,8 +1421,8 @@ github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250128203428-08031923fbe5/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/chains v0.0.0-20250124205858-500edf2db981 h1:svbNog045hGmbE3q10y3ijV55IgaqZMqvSnWGCa0d5w= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250124205858-500edf2db981/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a h1:fVtn9CDfoGF40FeqGwLvp9belfIw7VT3lgQTctFGP5E= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250203160922-fbdf168bb92a/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b h1:TO1pwFeQKDOmv3loFiLJvYhtymuTgQUw9WgtwK1rueg= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250121205514-f73e2f86c23b/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 h1:0ewLMbAz3rZrovdRUCgd028yOXX8KigB4FndAUdI2kM=