diff --git a/.github/workflows/cre-local-env-tests.yaml b/.github/workflows/cre-local-env-tests.yaml index 3ef9b6aea53..eff4e33f8ae 100644 --- a/.github/workflows/cre-local-env-tests.yaml +++ b/.github/workflows/cre-local-env-tests.yaml @@ -244,7 +244,6 @@ jobs: go run . env swap nodes - name: Execute example PoR workflow - if: false # TODO: Migrate example test to V2 and run here (DX-3233) shell: bash working-directory: core/scripts/cre/environment run: | diff --git a/core/scripts/cre/environment/README.md b/core/scripts/cre/environment/README.md index fbb4e31fc8b..e1f4ab68f36 100644 --- a/core/scripts/cre/environment/README.md +++ b/core/scripts/cre/environment/README.md @@ -186,12 +186,9 @@ Builds that access private repositories require `GITHUB_TOKEN` to be set (e.g. ` # while in core/scripts/cre/environment go run . env start [--auto-setup] -# to start environment with an example workflow web API-based workflow +# to start environment with the PoR v2 cron example workflow go run . env start --with-example - # to start environment with an example workflow cron-based workflow (requires cron capability in your image) -go run . env start --with-example --example-workflow-trigger cron - # to start environment with local Beholder go run . env start --with-beholder @@ -209,7 +206,6 @@ Optional parameters: - `-x`: Registers an example PoR workflow using CRE CLI and verifies it executed successfuly - `-s`: Time to wait for example workflow to execute successfuly (defaults to `5m`) - `-p`: **DEPRECATED** Use `image` in TOML config instead. See [Using a pre-built Chainlink image](#using-a-pre-built-chainlink-image). -- `-y`: Trigger for example workflow to deploy (web-trigger or cron). Default: `web-trigger`. **Important!** `cron` trigger requires the Chainlink image to include the cron capability (built from source or a pre-built image with plugins). - `--with-contracts-version`: Version of workflow/capability registries to use (`v2` by default, use `v1` explicitly for legacy coverage) ## Purging environment state @@ -434,12 +430,12 @@ go run . workflow delete-all [flags] go run . workflow delete-all ``` -### `workflow deploy-and-verify-example` -Deploys and verifies the example workflow. +### `workflow run-por-example` +Deploys and verifies the PoR v2 cron example workflow. **Usage:** ```bash -go run . workflow deploy-and-verify-example +go run . workflow run-por-example ``` This command uses default values and is useful for testing the workflow deployment process. @@ -886,58 +882,43 @@ The environment includes several example workflows located in `core/scripts/cre/ - **`v2/node-mode/`**: Node mode workflow example - **`v2/http/`**: HTTP-based workflow example -#### V1 Workflows -- **`v1/proof-of-reserve/cron-based/`**: Cron-based proof-of-reserve workflow -- **`v1/proof-of-reserve/web-trigger-based/`**: Web API trigger-based proof-of-reserve workflow +- **`v2/proof-of-reserve/cron-based/`**: Cron-based proof-of-reserve workflow example ### Deployable Example Workflows -The following workflows can be deployed using the `workflow deploy-and-verify-example` command: +The following workflow can be deployed using the `workflow run-por-example` command: -#### Proof-of-Reserve Workflows -Both proof-of-reserve workflows execute a proof-of-reserve-like scenario with the following steps: +#### Proof-of-Reserve Workflow +The proof-of-reserve workflow executes a proof-of-reserve-like scenario with the following steps: - Call external HTTP API and fetch value of test asset - Reach consensus on that value - Write that value in the consumer contract on chain **Usage:** ```bash -go run . workflow deploy-and-verify-example [flags] +go run . workflow run-por-example [flags] ``` **Key flags:** -- `-y, --example-workflow-trigger`: Trigger type (`web-trigger` or `cron`, default: `web-trigger`) - `-u, --example-workflow-timeout`: Time to wait for workflow execution (default: `5m`) -- `-g, --gateway-url`: Gateway URL for web API trigger (default: `http://localhost:5002`) -- `-d, --don-id`: DON ID for web API trigger (default: `vault`) +- `-d, --workflow-don-id`: Workflow DON ID from the registry (default: `1`) - `-w, --workflow-registry-address`: Workflow registry address (default: `0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0`) - `-r, --rpc-url`: RPC URL (default: `http://localhost:8545`) **Examples:** ```bash -# Deploy cron-based proof-of-reserve workflow -go run . workflow deploy-and-verify-example -y cron +# Deploy the PoR v2 cron example +go run . workflow run-por-example -# Deploy web-trigger-based proof-of-reserve workflow with custom timeout -go run . workflow deploy-and-verify-example -y web-trigger -u 10m +# Deploy the PoR v2 cron example with custom timeout +go run . workflow run-por-example -u 10m ``` #### Cron-based Workflow - **Trigger**: Every 30 seconds on a schedule - **Behavior**: Keeps executing until paused or deleted - **Requirements**: External `cron` capability binary (must be manually compiled or downloaded and configured in TOML) -- **Source**: [`examples/workflows/v1/proof-of-reserve/cron-based/main.go`](./examples/workflows/v1/proof-of-reserve/cron-based/main.go) - -#### Web API Trigger-based Workflow -- **Trigger**: Only when a precisely crafted and cryptographically signed request is made to the gateway node -- **Behavior**: Triggers workflow **once** and only if: - - Sender is whitelisted in the workflow - - Topic is whitelisted in the workflow -- **Source**: [`examples/workflows/v1/proof-of-reserve/web-trigger-based/main.go`](./examples/workflows/v1/proof-of-reserve/web-trigger-based/main.go) - -**Note**: You might see multiple attempts to trigger and verify the workflow when running the example. This is expected and could happen because: -- Topic hasn't been registered yet (nodes haven't downloaded the workflow yet) -- Consensus wasn't reached in time +- **Source**: [`examples/workflows/v2/proof-of-reserve/cron-based/main.go`](./examples/workflows/v2/proof-of-reserve/cron-based/main.go) ### Manual Workflow Deployment @@ -2121,4 +2102,4 @@ Once installed, configure it by running: gh auth login ``` -For GH CLI to be used by the environment to download the CRE CLI you must have access to [smartcontract/dev-platform](https://github.com/smartcontractkit/dev-platform) repository. \ No newline at end of file +For GH CLI to be used by the environment to download the CRE CLI you must have access to [smartcontract/dev-platform](https://github.com/smartcontractkit/dev-platform) repository. diff --git a/core/scripts/cre/environment/completions.go b/core/scripts/cre/environment/completions.go index 47ee879898b..cc8c902f197 100644 --- a/core/scripts/cre/environment/completions.go +++ b/core/scripts/cre/environment/completions.go @@ -244,7 +244,6 @@ func buildCommandTree() *CompletionNode { {Text: "--with-example", Description: "Deploys and registers example workflow (default: false)"}, {Text: "--example-workflow-timeout", Description: "Time to wait until example workflow succeeds (e.g. 10s, 1m, 1h) (default: 5m)"}, {Text: "--with-plugins-docker-image", Description: "Docker image to use (must have all capabilities included)"}, - {Text: "--example-workflow-trigger", Description: "Trigger for example workflow to deploy (web-trigger or cron) (default: web-trigger)"}, {Text: "--with-beholder", Description: "Deploys Beholder (Chip Ingress + Red Panda) (default: false)"}, {Text: "--with-dashboards", Description: "Deploys Observability Stack and Grafana Dashboards (default: false)"}, {Text: "--with-billing", Description: "Deploys Billing Platform Service (default: false)"}, @@ -296,7 +295,7 @@ func buildCommandTree() *CompletionNode { // ENV WORKFLOW - workflow management workflowNode := &CompletionNode{ Suggestions: []prompt.Suggest{ - {Text: "deploy-and-verify-example", Description: "Deploy and verify example workflow"}, + {Text: "run-por-example", Description: "Deploy and verify the PoR v2 cron example workflow"}, {Text: "delete", Description: "Delete a specific workflow"}, {Text: "delete-all", Description: "Delete all workflows"}, {Text: "compile", Description: "Compile a workflow specification"}, diff --git a/core/scripts/cre/environment/environment/environment.go b/core/scripts/cre/environment/environment/environment.go index ce29343e41d..58f11f11353 100644 --- a/core/scripts/cre/environment/environment/environment.go +++ b/core/scripts/cre/environment/environment/environment.go @@ -70,11 +70,6 @@ var ( provisioningStartTime time.Time ) -const ( - WorkflowTriggerWebTrigger = "web-trigger" - WorkflowTriggerCron = "cron" -) - var EnvironmentCmd = &cobra.Command{ Use: "env", Short: "Environment commands", @@ -216,7 +211,6 @@ func startCmd() *cobra.Command { var ( extraAllowedGatewayPorts []int withExampleFlag bool - exampleWorkflowTrigger string exampleWorkflowTimeout time.Duration withPluginsDockerImage string withContractsVersion string @@ -460,9 +454,6 @@ func startCmd() *cobra.Command { return errors.New("no gateway connector configurations found") } - // use first gateway for example workflow - gatewayURL := fmt.Sprintf("%s://%s:%d%s", output.GatewayConnectors.Configurations[0].Incoming.Protocol, output.GatewayConnectors.Configurations[0].Incoming.Host, output.GatewayConnectors.Configurations[0].Incoming.ExternalPort, output.GatewayConnectors.Configurations[0].Incoming.Path) - fmt.Print(libformat.PurpleText("\nRegistering and verifying example workflow\n\n")) workflowRegistryAddress := libcontracts.MustGetAddressFromDataStore(output.CreEnvironment.CldfEnvironment.DataStore, output.CreEnvironment.Blockchains[0].ChainSelector(), keystone_changeset.WorkflowRegistry.String(), output.CreEnvironment.ContractVersions[keystone_changeset.WorkflowRegistry.String()], "") @@ -478,11 +469,7 @@ func startCmd() *cobra.Command { return errors.New("no workflow DON found") } - workflowDON, wErr := output.Dons.OneDonWithFlag(cre.WorkflowDON) - if wErr != nil { - return errors.Wrap(wErr, "failed to get workflow DON") - } - deployErr := deployAndVerifyExampleWorkflow(cmdContext, registryChainOut.CtfOutput().Nodes[0].ExternalHTTPUrl, gatewayURL, workflowDON.Name, workflowDonID, exampleWorkflowTimeout, exampleWorkflowTrigger, workflowRegistryAddress, semver.MustParse(withContractsVersion)) + deployErr := deployAndVerifyExampleWorkflow(cmdContext, registryChainOut.CtfOutput().Nodes[0].ExternalHTTPUrl, workflowDonID, exampleWorkflowTimeout, workflowRegistryAddress, semver.MustParse(withContractsVersion)) if deployErr != nil { fmt.Printf("Failed to deploy and verify example workflow: %s\n", deployErr) } @@ -514,7 +501,6 @@ func startCmd() *cobra.Command { cmd.Flags().BoolVarP(&withExampleFlag, "with-example", "x", false, "Deploys and registers example workflow") cmd.Flags().DurationVarP(&exampleWorkflowTimeout, "example-workflow-timeout", "u", 5*time.Minute, "Time to wait until example workflow succeeds (e.g. 10s, 1m, 1h)") cmd.Flags().StringVarP(&withPluginsDockerImage, "with-plugins-docker-image", "p", "", "DEPRECATED:Docker image to use (set Docker image in TOML config instead)") - cmd.Flags().StringVarP(&exampleWorkflowTrigger, "example-workflow-trigger", "y", "web-trigger", "Trigger for example workflow to deploy (web-trigger or cron)") cmd.Flags().BoolVarP(&withBeholder, "with-beholder", "b", false, "Deploy Beholder (Chip Ingress + Red Panda)") cmd.Flags().BoolVarP(&withDashboards, "with-dashboards", "d", false, "Deploy Observability Stack and Grafana Dashboards") cmd.Flags().BoolVar(&withObs, "with-observability", false, "Start Observability Stack") diff --git a/core/scripts/cre/environment/environment/examples.go b/core/scripts/cre/environment/environment/examples.go index a6fe2e353b6..7a68acc841c 100644 --- a/core/scripts/cre/environment/environment/examples.go +++ b/core/scripts/cre/environment/environment/examples.go @@ -3,9 +3,9 @@ package environment import ( "context" "fmt" + "math/big" "os" "path/filepath" - "strings" "time" "github.com/Masterminds/semver/v3" @@ -14,34 +14,29 @@ import ( "github.com/spf13/cobra" "gopkg.in/yaml.v3" - "github.com/smartcontractkit/chainlink-testing-framework/framework" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" "github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/pkg/deploy" - "github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/pkg/trigger" "github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/pkg/verify" - cronbasedtypes "github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based/types" - webapitriggerbasedtypes "github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/types" + portypes "github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v2/proof-of-reserve/cron-based/types" keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment" creworkflow "github.com/smartcontractkit/chainlink/system-tests/lib/cre/workflow" libformat "github.com/smartcontractkit/chainlink/system-tests/lib/format" + corevm "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) func deployAndVerifyExampleWorkflowCmd() *cobra.Command { var ( rpcURLFlag string - gatewayURLFlag string workflowDonIDFlag uint32 - gatewayDonIDFlag string - exampleWorkflowTriggerFlag string exampleWorkflowTimeoutFlag string workflowRegistryAddressFlag string contractsVersionFlag string ) cmd := &cobra.Command{ Use: "run-por-example", - Short: "Runs v1 Proof-of-Reserve example workflow", - Long: `Deploys a simple Proof-of-Reserve workflow and, optionally, wait until it succeeds`, + Short: "Runs the PoR v2 cron example workflow", + Long: `Deploys the PoR v2 cron example workflow and waits until it succeeds`, PersistentPreRun: globalPreRunFunc, RunE: func(cmd *cobra.Command, args []string) error { timeout, timeoutErr := time.ParseDuration(exampleWorkflowTimeoutFlag) @@ -61,13 +56,6 @@ func deployAndVerifyExampleWorkflowCmd() *cobra.Command { } } - gatewayURL := gatewayURLFlag - if !cmd.Flags().Changed("gateway-url") && resolver != nil { - if stateGatewayURL, err := resolver.GatewayURL(); err == nil { - gatewayURL = stateGatewayURL - } - } - workflowDONID := workflowDonIDFlag if !cmd.Flags().Changed("workflow-don-id") && resolver != nil { if stateDONID, err := resolver.WorkflowDONID(); err == nil { @@ -75,75 +63,29 @@ func deployAndVerifyExampleWorkflowCmd() *cobra.Command { } } - gatewayDONName := gatewayDonIDFlag - if !cmd.Flags().Changed("gateway-don-id") && resolver != nil { - if stateDONName, err := resolver.WorkflowDONName(); err == nil { - gatewayDONName = stateDONName - } - } - workflowRegistryAddress, contractsVersion, err := resolveContractAddressAndVersion(cmd, resolver, keystone_changeset.WorkflowRegistry, workflowRegistryAddressFlag, contractsVersionFlag, "workflow-registry-address") if err != nil { return errors.Wrap(err, "❌ failed to resolve workflow registry") } - return deployAndVerifyExampleWorkflow(cmd.Context(), rpcURL, gatewayURL, gatewayDONName, workflowDONID, timeout, exampleWorkflowTriggerFlag, workflowRegistryAddress, contractsVersion) + return deployAndVerifyExampleWorkflow(cmd.Context(), rpcURL, workflowDONID, timeout, workflowRegistryAddress, contractsVersion) }, } cmd.Flags().StringVarP(&rpcURLFlag, "rpc-url", "r", "http://localhost:8545", "RPC URL") - cmd.Flags().StringVarP(&exampleWorkflowTriggerFlag, "example-workflow-trigger", "y", "web-trigger", "Trigger for example workflow to deploy (web-trigger or cron)") cmd.Flags().StringVarP(&exampleWorkflowTimeoutFlag, "example-workflow-timeout", "u", "5m", "Time to wait until example workflow succeeds (e.g. 10s, 1m, 1h)") - cmd.Flags().StringVarP(&gatewayURLFlag, "gateway-url", "g", "http://localhost:5002", "Gateway URL (only for web API trigger-based workflow)") cmd.Flags().Uint32VarP(&workflowDonIDFlag, "workflow-don-id", "d", 1, "DonID used in the workflow registry contract (integer starting with 1)") - cmd.Flags().StringVarP(&gatewayDonIDFlag, "gateway-don-id", "o", "workflow", "Name of the DON that is running web API trigger capability (only for web API trigger-based workflow)") cmd.Flags().StringVarP(&workflowRegistryAddressFlag, "workflow-registry-address", "w", "", "Workflow registry address (if not provided, address from the state file will be used)") - cmd.Flags().StringVar(&contractsVersionFlag, "with-contracts-version", "", "Version of workflow registry contract to use (v1 or v2)") + cmd.Flags().StringVar(&contractsVersionFlag, "with-contracts-version", "v2", "Version of workflow registry contract to use (v1 or v2)") return cmd } -type executableWorkflowFn = func(cmdContext context.Context, rpcURL, gatewayURL, gatewayDonID, privateKey string, consumerContractAddress common.Address, feedID string, waitTime time.Duration, startTime time.Time) error - -func executeWebTriggerBasedWorkflow(cmdContext context.Context, rpcURL, gatewayURL, gatewayDonID, privateKey string, consumerContractAddress common.Address, feedID string, waitTime time.Duration, startTime time.Time) error { - ticker := 5 * time.Second - for { - select { - case <-time.After(waitTime): - fmt.Print(libformat.PurpleText("\n[Stage 3/3] Example workflow failed to execute successfully in %.2f seconds\n", time.Since(startTime).Seconds())) - - return fmt.Errorf("example workflow failed to execute successfully within %s", waitTime) - case <-time.Tick(ticker): - triggerErr := trigger.WebAPITriggerValue( - gatewayURL, - gatewayDonID, - privateKey, - 5*time.Minute, - ) - if triggerErr == nil { - verifyTime := 25 * time.Second - verifyErr := verify.ProofOfReserve(rpcURL, consumerContractAddress.Hex(), feedID, true, verifyTime) - if verifyErr == nil { - if isBlockscoutRunning(cmdContext) { - fmt.Print(libformat.PurpleText("Open http://localhost/address/%s?tab=internal_txns to check consumer contract's transaction history\n", consumerContractAddress.Hex())) - } - - return nil - } - - fmt.Printf("\nTrying to verify workflow again in %.2f seconds...\n\n", ticker.Seconds()) - } else { - framework.L.Debug().Msgf("failed to trigger web API trigger: %s", triggerErr) - } - } - } -} - -func executeCronBasedWorkflow(cmdContext context.Context, rpcURL, _, _, privateKey string, consumerContractAddress common.Address, feedID string, waitTime time.Duration, startTime time.Time) error { +func executeCronBasedWorkflow(cmdContext context.Context, rpcURL string, consumerContractAddress common.Address, feedID string, waitTime time.Duration, startTime time.Time) error { // we ignore return as if verification failed it will print that info verifyErr := verify.ProofOfReserve(rpcURL, consumerContractAddress.Hex(), feedID, true, waitTime) if verifyErr != nil { - fmt.Print(libformat.PurpleText("\n[Stage 3/3] Example workflow failed to execute successfully in %.2f seconds\n", time.Since(startTime).Seconds())) + fmt.Print(libformat.PurpleText("\n[Stage 4/4] Example workflow failed to execute successfully in %.2f seconds\n", time.Since(startTime).Seconds())) return errors.Wrap(verifyErr, "failed to verify example workflow") } @@ -154,7 +96,7 @@ func executeCronBasedWorkflow(cmdContext context.Context, rpcURL, _, _, privateK return nil } -func deployAndVerifyExampleWorkflow(cmdContext context.Context, rpcURL, gatewayURL, gatewayDonID string, workflowDonID uint32, timeout time.Duration, exampleWorkflowTrigger, workflowRegistryAddress string, contractsVersion *semver.Version) error { +func deployAndVerifyExampleWorkflow(cmdContext context.Context, rpcURL string, workflowDonID uint32, timeout time.Duration, workflowRegistryAddress string, contractsVersion *semver.Version) error { totalStart := time.Now() start := time.Now() @@ -179,32 +121,32 @@ func deployAndVerifyExampleWorkflow(cmdContext context.Context, rpcURL, gatewayU fmt.Print(libformat.PurpleText("\n[Stage 2/4] Deployed Balance Reader in %.2f seconds\n", time.Since(start).Seconds())) start = time.Now() - fmt.Print(libformat.PurpleText("[Stage 3/4] Registering example Proof-of-Reserve workflow\n\n")) + fmt.Print(libformat.PurpleText("[Stage 3/4] Registering PoR v2 cron example workflow\n\n")) - var executableWorkflowFunction executableWorkflowFn - - var workflowName string - var workflowFilePath string - var configFilePath string - var configErr error + workflowName := "por-v2-cron-example" + workflowFilePath := "examples/workflows/v2/proof-of-reserve/cron-based/main.go" feedID := "0x018e16c39e0003200000000000000000" + chainID, chainSelector, chainErr := deploy.ChainMetadata(rpcURL) + if chainErr != nil { + return errors.Wrap(chainErr, "failed to resolve chain metadata for PoR config") + } - if strings.EqualFold(exampleWorkflowTrigger, WorkflowTriggerCron) { - workflowName = "cron-based-proof-of-reserve" - workflowFilePath = "examples/workflows/v1/proof-of-reserve/cron-based/main.go" - configFilePath, configErr = builAndSavePoRCronConfig(consumerContractAddress.Hex(), balanceReaderContractAddress.Hex(), feedID, filepath.Dir(workflowFilePath)) - if configErr != nil { - return errors.Wrap(configErr, "failed to build and save PoR config") - } - executableWorkflowFunction = executeCronBasedWorkflow - } else { - workflowName = "web-trigger-based-proof-of-reserve" - workflowFilePath = "examples/workflows/v1/proof-of-reserve/web-trigger-based/main.go" - configFilePath, configErr = builAndSavePoRWebTriggerConfig(consumerContractAddress.Hex(), balanceReaderContractAddress.Hex(), feedID, filepath.Dir(workflowFilePath)) - if configErr != nil { - return errors.Wrap(configErr, "failed to build and save PoR config") - } - executableWorkflowFunction = executeWebTriggerBasedWorkflow + addressesToRead, addressesErr := deploy.CreateAndFundAddresses(rpcURL, 2, big.NewInt(10)) + if addressesErr != nil { + return errors.Wrap(addressesErr, "failed to create and fund addresses for PoR config") + } + + configFilePath, configErr := buildAndSavePoRV2CronConfig( + consumerContractAddress.Hex(), + balanceReaderContractAddress.Hex(), + feedID, + chainSelector, + corevm.GenerateWriteTargetName(chainID), + addressesToRead, + filepath.Dir(workflowFilePath), + ) + if configErr != nil { + return errors.Wrap(configErr, "failed to build and save PoR config") } defer func() { @@ -241,54 +183,29 @@ func deployAndVerifyExampleWorkflow(cmdContext context.Context, rpcURL, gatewayU return pkErr } - return executableWorkflowFunction(cmdContext, rpcURL, gatewayURL, gatewayDonID, os.Getenv("PRIVATE_KEY"), *consumerContractAddress, feedID, timeout, totalStart) + return executeCronBasedWorkflow(cmdContext, rpcURL, *consumerContractAddress, feedID, timeout, totalStart) } -func builAndSavePoRWebTriggerConfig(dataFeedsCacheAddress, balanceReaderAddress, feedID, folder string) (string, error) { - cfg := webapitriggerbasedtypes.WorkflowConfig{ - DataFeedsCacheAddress: dataFeedsCacheAddress, - AllowedTriggerSender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - AllowedTriggerTopic: "sendValue", - FeedID: feedID, - WriteTargetName: "write_geth-testnet@1.0.0", - ChainFamily: "evm", - ChainID: "1337", - BalanceReaderConfig: webapitriggerbasedtypes.BalanceReaderConfig{ - BalanceReaderAddress: balanceReaderAddress, - }, - } - - yaml, yamlErr := yaml.Marshal(cfg) - if yamlErr != nil { - return "", errors.Wrap(yamlErr, "failed to marshal config to YAML") - } - - filePath := filepath.Join(folder, "web_trigger_config.yaml") - writeErr := os.WriteFile(filePath, yaml, 0644) //nolint:gosec // G306: we want it to be readable by everyone - if writeErr != nil { - return "", errors.Wrap(writeErr, "failed to write config to file") - } - - return filePath, nil -} - -func builAndSavePoRCronConfig(dataFeedsCacheAddress, balanceReaderAddress, feedID, folder string) (string, error) { +func buildAndSavePoRV2CronConfig(dataFeedsCacheAddress, balanceReaderAddress, feedID string, chainSelector uint64, writeTargetName string, addressesToRead []common.Address, folder string) (string, error) { if feedID == "" { return "", errors.New("feedID is empty") } + if len(addressesToRead) < 2 { + return "", errors.New("at least two addresses are required for the PoR v2 example") + } - cfg := cronbasedtypes.WorkflowConfig{ - ComputeConfig: cronbasedtypes.ComputeConfig{ + cfg := portypes.WorkflowConfig{ + ChainSelector: chainSelector, + ComputeConfig: portypes.ComputeConfig{ DataFeedsCacheAddress: dataFeedsCacheAddress, URL: "https://api.real-time-reserves.verinumus.io/v1/chainlink/proof-of-reserves/TrueUSD", FeedID: feedID, - WriteTargetName: "write_geth-testnet@1.0.0", + WriteTargetName: writeTargetName, }, - BalanceReaderConfig: cronbasedtypes.BalanceReaderConfig{ + BalanceReaderConfig: portypes.BalanceReaderConfig{ BalanceReaderAddress: balanceReaderAddress, + AddressesToRead: addressesToRead, }, - ChainFamily: "evm", - ChainID: "1337", } yaml, yamlErr := yaml.Marshal(cfg) @@ -296,7 +213,7 @@ func builAndSavePoRCronConfig(dataFeedsCacheAddress, balanceReaderAddress, feedI return "", errors.Wrap(yamlErr, "failed to marshal config to YAML") } - filePath := filepath.Join(folder, "cron_config.yaml") + filePath := filepath.Join(folder, "config.yaml") writeErr := os.WriteFile(filePath, yaml, 0644) //nolint:gosec // G306: we want it to be readable by everyone if writeErr != nil { return "", errors.Wrap(writeErr, "failed to write config to file") diff --git a/core/scripts/cre/environment/environment/state_resolver_test.go b/core/scripts/cre/environment/environment/state_resolver_test.go deleted file mode 100644 index cf6e2ee3a20..00000000000 --- a/core/scripts/cre/environment/environment/state_resolver_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package environment - -import ( - "os" - "testing" - - "github.com/Masterminds/semver/v3" - "github.com/spf13/cobra" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-deployments-framework/datastore" - keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" - "github.com/smartcontractkit/chainlink/system-tests/lib/cre" - envconfig "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/config" - "github.com/smartcontractkit/chainlink/system-tests/lib/infra" -) - -func TestResolverAddressRef(t *testing.T) { - t.Parallel() - - cfg := &envconfig.Config{} - require.NoError(t, cfg.SetAddresses([]datastore.AddressRef{{ - Address: "0x123", - Type: datastore.ContractType(keystone_changeset.WorkflowRegistry), - ChainSelector: 1337, - Version: semver.MustParse("2.0.0"), - }})) - - resolver := &LocalCREStateResolver{cfg: cfg} - - addrRef, err := resolver.AddressRef(keystone_changeset.WorkflowRegistry) - require.NoError(t, err) - require.Equal(t, "0x123", addrRef.Address) - require.Equal(t, uint64(1337), addrRef.ChainSelector) - require.Equal(t, semver.MustParse("2.0.0").String(), addrRef.Version.String()) -} - -func TestResolverWorkflowDONMetadata(t *testing.T) { - t.Parallel() - - donsMetadata, err := cre.NewDonsMetadata([]*cre.DonMetadata{{ - Name: "workflow-don", - ID: 7, - Flags: []string{cre.WorkflowDON}, - NodesMetadata: []*cre.NodeMetadata{{ - Roles: []string{cre.BootstrapNode}, - }}, - }}, infra.Provider{Type: infra.Docker}) - require.NoError(t, err) - - resolver := &LocalCREStateResolver{ - topology: &cre.Topology{DonsMetadata: donsMetadata}, - } - - workflowDON, err := resolver.WorkflowDONMetadata() - require.NoError(t, err) - require.Equal(t, "workflow-don", workflowDON.Name) - - workflowDONID, err := resolver.WorkflowDONID() - require.NoError(t, err) - require.Equal(t, uint32(7), workflowDONID) - - workflowDONName, err := resolver.WorkflowDONName() - require.NoError(t, err) - require.Equal(t, "workflow-don", workflowDONName) -} - -func TestResolverGatewayURLFallsBackToProviderHost(t *testing.T) { - t.Parallel() - - resolver := &LocalCREStateResolver{ - cfg: &envconfig.Config{ - Infra: &infra.Provider{Type: infra.Docker}, - }, - topology: &cre.Topology{ - GatewayConnectors: &cre.GatewayConnectors{ - Configurations: []*cre.DonGatewayConfiguration{{ - GatewayConfiguration: &cre.GatewayConfiguration{ - Incoming: cre.Incoming{ - Protocol: "http", - ExternalPort: 5002, - Path: "/", - }, - }, - }}, - }, - }, - } - - gatewayURL, err := resolver.GatewayURL() - require.NoError(t, err) - require.Equal(t, "http://localhost:5002/", gatewayURL) -} - -func TestResolveContractAddressAndVersion(t *testing.T) { - t.Parallel() - - makeCmd := func(address string) *cobra.Command { - cmd := newCobraCommand() - cmd.Flags().String("workflow-registry-address", "", "") - require.NoError(t, cmd.Flags().Set("workflow-registry-address", address)) - return cmd - } - - t.Run("uses state when flag not changed", func(t *testing.T) { - cfg := &envconfig.Config{} - require.NoError(t, cfg.SetAddresses([]datastore.AddressRef{{ - Address: "0x456", - Type: datastore.ContractType(keystone_changeset.WorkflowRegistry), - Version: semver.MustParse("1.1.0"), - }})) - - cmd := newCobraCommand() - cmd.Flags().String("workflow-registry-address", "", "") - - address, version, err := resolveContractAddressAndVersion(cmd, &LocalCREStateResolver{cfg: cfg}, keystone_changeset.WorkflowRegistry, "", "2.0.0", "workflow-registry-address") - require.NoError(t, err) - require.Equal(t, "0x456", address) - require.Equal(t, "1.1.0", version.String()) - }) - - t.Run("uses explicit override when flag changed", func(t *testing.T) { - cmd := makeCmd("0xabc") - - address, version, err := resolveContractAddressAndVersion(cmd, nil, keystone_changeset.WorkflowRegistry, "0xabc", "2.0.0", "workflow-registry-address") - require.NoError(t, err) - require.Equal(t, "0xabc", address) - require.Equal(t, "2.0.0", version.String()) - }) -} - -func TestToDockerHostRPC(t *testing.T) { - t.Parallel() - - expected := "http://host.docker.internal:8545" - if os.Getenv("CI") == "true" { - expected = "http://172.17.0.1:8545" - } - - require.Equal(t, expected, toDockerHostRPC("http://localhost:8545")) - require.Equal(t, expected, toDockerHostRPC("http://127.0.0.1:8545")) -} - -func newCobraCommand() *cobra.Command { - return &cobra.Command{Use: "test"} -} diff --git a/core/scripts/cre/environment/examples/pkg/deploy/consumer.go b/core/scripts/cre/environment/examples/pkg/deploy/consumer.go index d345f675af9..3e9a2943503 100644 --- a/core/scripts/cre/environment/examples/pkg/deploy/consumer.go +++ b/core/scripts/cre/environment/examples/pkg/deploy/consumer.go @@ -1,18 +1,24 @@ package deploy import ( + "context" + "math/big" "os" "time" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + chainselectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-testing-framework/framework" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/seth" "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/balance_reader" "github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/contracts/permissionless_feeds_consumer" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment" + crecrypto "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" + libfunding "github.com/smartcontractkit/chainlink/system-tests/lib/funding" ) func PermissionlessFeedsConsumer(rpcURL string) (*common.Address, error) { @@ -70,3 +76,70 @@ func BalanceReader(rpcURL string) (*common.Address, error) { return &data.Address, nil } + +func ChainMetadata(rpcURL string) (uint64, uint64, error) { + sethClient, err := newSethClient(rpcURL) + if err != nil { + return 0, 0, err + } + + chainID := sethClient.Cfg.Network.ChainID + chainSelector, err := chainselectors.SelectorFromChainId(chainID) + if err != nil { + return 0, 0, errors.Wrapf(err, "failed to resolve chain selector for chain id %d", chainID) + } + + return chainID, chainSelector, nil +} + +func CreateAndFundAddresses(rpcURL string, count int, amount *big.Int) ([]common.Address, error) { + if count <= 0 { + return nil, errors.New("count must be greater than zero") + } + if amount == nil { + return nil, errors.New("amount is nil") + } + + sethClient, err := newSethClient(rpcURL) + if err != nil { + return nil, err + } + + addresses := make([]common.Address, 0, count) + for range count { + address, _, err := crecrypto.GenerateNewKeyPair() + if err != nil { + return nil, errors.Wrap(err, "failed to generate address") + } + + _, err = libfunding.SendFunds(context.Background(), framework.L, sethClient, libfunding.FundsToSend{ + ToAddress: address, + Amount: new(big.Int).Set(amount), + PrivateKey: sethClient.MustGetRootPrivateKey(), + }) + if err != nil { + return nil, errors.Wrapf(err, "failed to fund address %s", address.Hex()) + } + + addresses = append(addresses, address) + } + + return addresses, nil +} + +func newSethClient(rpcURL string) (*seth.Client, error) { + if pkErr := environment.SetDefaultPrivateKeyIfEmpty(blockchain.DefaultAnvilPrivateKey); pkErr != nil { + return nil, pkErr + } + + sethClient, sethErr := seth.NewClientBuilder(). + WithRpcUrl(rpcURL). + WithPrivateKeys([]string{os.Getenv("PRIVATE_KEY")}). + WithProtections(false, false, seth.MustMakeDuration(time.Second)). + Build() + if sethErr != nil { + return nil, errors.Wrap(sethErr, "failed to create Seth Ethereum client") + } + + return sethClient, nil +} diff --git a/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/go.mod b/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/go.mod deleted file mode 100644 index 7ea8adc9e3a..00000000000 --- a/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/go.mod +++ /dev/null @@ -1,91 +0,0 @@ -module github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based - -go 1.25.7 - -require ( - github.com/smartcontractkit/chainlink-common v0.10.1-0.20260317233127-178dd2eeaa87 - github.com/smartcontractkit/chainlink/v2 v2.32.0 - gopkg.in/yaml.v3 v3.0.1 -) - -require ( - github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c // indirect - github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/buger/jsonparser v1.1.1 // indirect - github.com/cenkalti/backoff/v5 v5.0.3 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.2 // indirect - github.com/cloudevents/sdk-go/v2 v2.16.2 // indirect - github.com/fatih/color v1.18.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.10 // indirect - github.com/go-logr/logr v1.4.3 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.28.0 // indirect - github.com/go-viper/mapstructure/v2 v2.5.0 // indirect - github.com/goccy/go-yaml v1.12.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect - github.com/iancoleman/strcase v0.3.0 // indirect - github.com/invopop/jsonschema v0.13.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mr-tron/base58 v1.2.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.23.2 // indirect - github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect - github.com/sanity-io/litter v1.5.5 // indirect - github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect - github.com/shopspring/decimal v1.4.0 // indirect - github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 // indirect - github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect - go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect - go.opentelemetry.io/otel v1.41.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 // indirect - go.opentelemetry.io/otel/log v0.15.0 // indirect - go.opentelemetry.io/otel/metric v1.41.0 // indirect - go.opentelemetry.io/otel/sdk v1.41.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.15.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.41.0 // indirect - go.opentelemetry.io/otel/trace v1.41.0 // indirect - go.opentelemetry.io/proto/otlp v1.9.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.48.0 // indirect - golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.50.0 // indirect - golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.0 // indirect - golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect - google.golang.org/grpc v1.78.0 // indirect - google.golang.org/protobuf v1.36.11 // indirect -) diff --git a/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/go.sum b/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/go.sum deleted file mode 100644 index 4b933398b36..00000000000 --- a/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/go.sum +++ /dev/null @@ -1,213 +0,0 @@ -github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c h1:cxQVoh6kY+c4b0HUchHjGWBI8288VhH50qxKG3hdEg0= -github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c/go.mod h1:3XzxudkrYVUvbduN/uI2fl4lSrMSzU0+3RCu2mpnfx8= -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= -github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.2 h1:ydUjnKn4RoCeN8rge3F/deT52w2WJMmIC5mHNUq+Ut8= -github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.2/go.mod h1:Bny999RuVUtNjzTGa9HCHpXjrLGMipJVq5kqVpudBl0= -github.com/cloudevents/sdk-go/v2 v2.16.2 h1:ZYDFrYke4FD+jM8TZTJJO6JhKHzOQl2oqpFK1D+NnQM= -github.com/cloudevents/sdk-go/v2 v2.16.2/go.mod h1:laOcGImm4nVJEU+PHnUrKL56CKmRL65RlQF0kRmW/kg= -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= -github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= -github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= -github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= -github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= -github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM= -github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= -github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= -github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= -github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= -github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= -github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= -github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= -github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= -github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= -github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260317233127-178dd2eeaa87 h1:nvv1kiv/7jwALkFztO//NhIq4Y9M4kmJ0UCgTZMC/qI= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260317233127-178dd2eeaa87/go.mod h1:0ghbAr7tRO0tT5ZqBXhOyzgUO37tNNe33Yn0hskauVM= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= -github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 h1:03tbcwjyIEjvHba1IWOj1sfThwebm2XNzyFHSuZtlWc= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/chainlink/v2 v2.32.0 h1:Fax3JOIAa0uvthgLsd34ktekmSkrDMP2rl0/KFVugcY= -github.com/smartcontractkit/chainlink/v2 v2.32.0/go.mod h1:MIh2RAuTXdC3voDTo5+AtPyJPQfeIH5hkBDZQ0P1tjg= -github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e h1:poXTj5cFVM6XfC4HICIDYkDVc/A6OYB0eeID0wU2JQE= -github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e/go.mod h1:PLdNK6GlqfxIWXzziPkU7dCAVlVFeYkyyW7AQY0R+4Q= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= -github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= -go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= -go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= -go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= -go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 h1:06ZeJRe5BnYXceSM9Vya83XXVaNGe3H1QqsvqRANQq8= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2/go.mod h1:DvPtKE63knkDVP88qpatBj81JxN+w1bqfVbsbCbj1WY= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 h1:tPLwQlXbJ8NSOfZc4OkgU5h2A38M4c9kfHSVc4PFQGs= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2/go.mod h1:QTnxBwT/1rBIgAG1goq6xMydfYOBKU6KTiYF4fp5zL8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0 h1:gAU726w9J8fwr4qRDqu1GYMNNs4gXrU+Pv20/N1UpB4= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0/go.mod h1:RboSDkp7N292rgu+T0MgVt2qgFGu6qa1RpZDOtpL76w= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= -go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0 h1:yEX3aC9KDgvYPhuKECHbOlr5GLwH6KTjLJ1sBSkkxkc= -go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0/go.mod h1:/GXR0tBmmkxDaCUGahvksvp66mx4yh5+cFXgSlhg0vQ= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 h1:G8Xec/SgZQricwWBJF/mHZc7A02YHedfFDENwJEdRA0= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/AiFD5aqoxGxCvT/ILJPeHy3MjqU/NS7KogY= -go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= -go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= -go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ= -go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps= -go.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8= -go.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90= -go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE= -go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ= -go.opentelemetry.io/otel/sdk/log/logtest v0.13.0 h1:9yio6AFZ3QD9j9oqshV1Ibm9gPLlHNxurno5BreMtIA= -go.opentelemetry.io/otel/sdk/log/logtest v0.13.0/go.mod h1:QOGiAJHl+fob8Nu85ifXfuQYmJTFAvcrxL6w5/tu168= -go.opentelemetry.io/otel/sdk/metric v1.41.0 h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8= -go.opentelemetry.io/otel/sdk/metric v1.41.0/go.mod h1:HNBuSvT7ROaGtGI50ArdRLUnvRTRGniSUZbxiWxSO8Y= -go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0= -go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis= -go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= -go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= -golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= -gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 h1:X9z6obt+cWRX8XjDVOn+SZWhWe5kZHm46TThU9j+jss= -google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3/go.mod h1:dd646eSK+Dk9kxVBl1nChEOhJPtMXriCcVb4x3o6J+E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= -google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= -google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= -google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/main.go b/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/main.go deleted file mode 100644 index 6a934b44567..00000000000 --- a/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/main.go +++ /dev/null @@ -1,171 +0,0 @@ -package main - -import ( - "encoding/hex" - "fmt" - "math/big" - "time" - - "gopkg.in/yaml.v3" - - "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/aggregators" - "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/ocr3cap" - "github.com/smartcontractkit/chainlink-common/pkg/capabilities/targets/chainwriter" - "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk" - "github.com/smartcontractkit/chainlink-common/pkg/workflows/wasm" - types "github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/types" - "github.com/smartcontractkit/chainlink/v2/core/capabilities/webapi/webapicap" -) - -func main() { - runner := wasm.NewRunner() - workflow, err := valueTriggeredWorkflow(runner) - if err != nil { - panic(err) - } - runner.Run(workflow) -} - -func valueTriggeredWorkflow(r sdk.Runner) (*sdk.WorkflowSpecFactory, error) { - var workflowConfig types.WorkflowConfig - if err := yaml.Unmarshal(r.Config(), &workflowConfig); err != nil { - return nil, err - } - - w := sdk.NewWorkflowSpecFactory() - - // Web API Trigger: define allowed sender, rate limits, required parameters - trigger := webapicap.TriggerConfig{ - AllowedSenders: []string{workflowConfig.AllowedTriggerSender}, - AllowedTopics: []string{workflowConfig.AllowedTriggerTopic}, - RateLimiter: webapicap.RateLimiterConfig{ - GlobalBurst: 1000, - GlobalRPS: 1000, - PerSenderBurst: 1000, - PerSenderRPS: 1000, - }, - RequiredParams: []string{"value"}, - }.New(w) - - // Compute: get value from event - contractValue := sdk.Compute1( - w, - "getValue", - sdk.Compute1Inputs[webapicap.TriggerRequestPayloadParams]{Arg0: trigger.Params().(sdk.CapDefinition[webapicap.TriggerRequestPayloadParams])}, - func(SDK sdk.Runtime, o webapicap.TriggerRequestPayloadParams) (ValueOutput, error) { - if len(o) == 0 { - return ValueOutput{}, fmt.Errorf("no data found in event") - } - - maybeValue, ok := o["value"] - if !ok { - return ValueOutput{}, fmt.Errorf("value with name 'value' not found in payload") - } - - valueStr, ok := maybeValue.(string) - if !ok { - return ValueOutput{}, fmt.Errorf("value is not a string, but %T", maybeValue) - } - - valueBigInt := new(big.Int) - valueBigInt, ok = valueBigInt.SetString(valueStr, 10) - if !ok { - return ValueOutput{}, fmt.Errorf("failed to convert value %s to big.Int", valueStr) - } - - // Convert the FeedID string to a byte array - feedIDBytes, err := convertFeedIDtoBytes(workflowConfig.FeedID) - if err != nil { - return ValueOutput{}, fmt.Errorf("failed to convert FeedID to bytes: %w", err) - } - - return ValueOutput{ - Price: valueBigInt, - Timestamp: time.Now().Unix(), - FeedID: feedIDBytes, - }, nil - }, - ) - - // Consensus: all observations are aggregated, timestamps can be maximum 30 seconds apart - // median of all values is used as the value price - consensusInput := ocr3cap.ReduceConsensusInput[ValueOutput]{ - Observation: contractValue.Value(), - } - - consensus := ocr3cap.ReduceConsensusConfig[ValueOutput]{ - Encoder: ocr3cap.EncoderEVM, - EncoderConfig: map[string]any{ - "abi": "(bytes32 FeedID, uint32 Timestamp, uint224 Price)[] Reports", - }, - ReportID: "0001", - KeyID: "evm", - AggregationConfig: aggregators.ReduceAggConfig{ - Fields: []aggregators.AggregationField{ - { - InputKey: "FeedID", - OutputKey: "FeedID", - Method: "mode", - }, - { - InputKey: "Price", - OutputKey: "Price", - Method: "median", - DeviationType: "any", - }, - { - InputKey: "Timestamp", - OutputKey: "Timestamp", - Method: "median", - DeviationString: "30", - DeviationType: "absolute", - }, - }, - ReportFormat: aggregators.REPORT_FORMAT_ARRAY, - }, - }.New(w, "consensus", consensusInput) - - // Write: write the median price to the Data Feeds Cache contract - targetInput := chainwriter.TargetInput{ - SignedReport: consensus, - } - - writeTargetName := "write_geth-testnet@1.0.0" - if workflowConfig.WriteTargetName != "" { - writeTargetName = workflowConfig.WriteTargetName - } - - chainwriter.TargetConfig{ - CreStepTimeout: 40, // 10 seconds - Address: workflowConfig.DataFeedsCacheAddress, // Data Feeds Cache contract address - DeltaStage: "15s", - Schedule: "oneAtATime", - }.New(w, writeTargetName, targetInput) - - return w, nil -} - -func Ptr[T any](v T) *T { - return &v -} - -func convertFeedIDtoBytes(feedIDStr string) ([32]byte, error) { - b, err := hex.DecodeString(feedIDStr[2:]) - if err != nil { - return [32]byte{}, err - } - - if len(b) < 32 { - nb := [32]byte{} - copy(nb[:], b[:]) - return nb, err - } - - return [32]byte(b), nil -} - -type ValueOutput struct { - Price *big.Int - Timestamp int64 - FeedID [32]byte -} diff --git a/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/types/types.go b/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/types/types.go deleted file mode 100644 index bddb2a4d49e..00000000000 --- a/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based/types/types.go +++ /dev/null @@ -1,16 +0,0 @@ -package types - -type WorkflowConfig struct { - WriteTargetName string `yaml:"write_target_name"` - ChainFamily string `yaml:"chain_family,omitempty"` - ChainID string `yaml:"chain_id,omitempty"` - DataFeedsCacheAddress string `yaml:"data_feeds_cache_address"` - AllowedTriggerSender string `yaml:"allowed_trigger_sender"` - AllowedTriggerTopic string `yaml:"allowed_trigger_topic"` - FeedID string `yaml:"feed_id"` - BalanceReaderConfig -} - -type BalanceReaderConfig struct { - BalanceReaderAddress string `yaml:"balance_reader_address"` -} diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 0f78424baa2..a66700febe8 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -9,9 +9,7 @@ replace github.com/smartcontractkit/chainlink/deployment => ../../deployment replace github.com/smartcontractkit/chainlink/system-tests/lib => ../../system-tests/lib -replace github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based => ./cre/environment/examples/workflows/v1/proof-of-reserve/cron-based - -replace github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based => ./cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based +replace github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v2/proof-of-reserve/cron-based => ./cre/environment/examples/workflows/v2/proof-of-reserve/cron-based // Using a separate `require` here to avoid surrounding line changes // creating potential merge conflicts. @@ -44,6 +42,7 @@ require ( github.com/prometheus/client_golang v1.23.2 github.com/rs/zerolog v1.34.0 github.com/shopspring/decimal v1.4.0 + github.com/smartcontractkit/chain-selectors v1.0.97 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-common v0.11.1 @@ -58,8 +57,7 @@ require ( github.com/smartcontractkit/chainlink-testing-framework/framework/components/dockercompose v0.1.20 github.com/smartcontractkit/chainlink-testing-framework/lib v1.54.5 github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.5 - github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based v0.0.0-20251020210257-0a6ec41648b4 - github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based v0.0.0-20251020210257-0a6ec41648b4 + github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v2/proof-of-reserve/cron-based v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/system-tests/lib v0.0.0-20251020210257-0a6ec41648b4 github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v1.3.0 github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e @@ -485,7 +483,6 @@ require ( github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/smartcontractkit/ccip-contract-examples/chains/evm v0.0.0-20260129135848-c86808ba5cb9 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect - github.com/smartcontractkit/chain-selectors v1.0.97 // indirect github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 // indirect github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm v0.0.0-20260323224438-d819cb3228e1 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 // indirect diff --git a/go.md b/go.md index a0c66e56c00..de581d56cd2 100644 --- a/go.md +++ b/go.md @@ -432,14 +432,11 @@ flowchart LR click chainlink-ton/deployment href "https://github.com/smartcontractkit/chainlink-ton" chainlink-tron/relayer --> chainlink-common click chainlink-tron/relayer href "https://github.com/smartcontractkit/chainlink-tron" - chainlink/core/scripts --> chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based - chainlink/core/scripts --> chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based + chainlink/core/scripts --> chainlink/core/scripts/cre/environment/examples/workflows/v2/proof-of-reserve/cron-based chainlink/core/scripts --> chainlink/system-tests/lib click chainlink/core/scripts href "https://github.com/smartcontractkit/chainlink" chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based --> chainlink-common click chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based href "https://github.com/smartcontractkit/chainlink" - chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based --> chainlink/v2 - click chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based href "https://github.com/smartcontractkit/chainlink" chainlink/core/scripts/cre/environment/examples/workflows/v2/cron --> cre-sdk-go/capabilities/scheduler/cron click chainlink/core/scripts/cre/environment/examples/workflows/v2/cron href "https://github.com/smartcontractkit/chainlink" chainlink/core/scripts/cre/environment/examples/workflows/v2/proof-of-reserve/cron-based --> chainlink-common @@ -572,7 +569,6 @@ flowchart LR subgraph chainlink-repo[chainlink] chainlink/core/scripts chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based - chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based chainlink/core/scripts/cre/environment/examples/workflows/v2/cron chainlink/core/scripts/cre/environment/examples/workflows/v2/proof-of-reserve/cron-based chainlink/deployment