diff --git a/deployment/common/changeset/test_helpers.go b/deployment/common/changeset/test_helpers.go index d0a472ccd8c..5e3dc928849 100644 --- a/deployment/common/changeset/test_helpers.go +++ b/deployment/common/changeset/test_helpers.go @@ -96,14 +96,25 @@ func ApplyChangesets(t *testing.T, e deployment.Environment, timelockContractsPe if out.MCMSTimelockProposals != nil { for _, prop := range out.MCMSTimelockProposals { mcmProp := proposalutils.SignMCMSTimelockProposal(t, e, &prop) - proposalutils.ExecuteMCMSProposalV2(t, e, mcmProp) - proposalutils.ExecuteMCMSTimelockProposalV2(t, e, &prop) + // return the error so devs can ensure expected reversions + err = proposalutils.ExecuteMCMSProposalV2(t, e, mcmProp) + if err != nil { + return deployment.Environment{}, err + } + err = proposalutils.ExecuteMCMSTimelockProposalV2(t, e, &prop) + if err != nil { + return deployment.Environment{}, err + } } } if out.MCMSProposals != nil { for _, prop := range out.MCMSProposals { p := proposalutils.SignMCMSProposal(t, e, &prop) - proposalutils.ExecuteMCMSProposalV2(t, e, p) + // return the error so devs can ensure expected reversions + err = proposalutils.ExecuteMCMSProposalV2(t, e, p) + if err != nil { + return deployment.Environment{}, err + } } } currentEnv = deployment.Environment{ diff --git a/deployment/common/proposalutils/mcms_test_helpers.go b/deployment/common/proposalutils/mcms_test_helpers.go index c49dddcc301..a3e3047fa2e 100644 --- a/deployment/common/proposalutils/mcms_test_helpers.go +++ b/deployment/common/proposalutils/mcms_test_helpers.go @@ -2,6 +2,7 @@ package proposalutils import ( "crypto/ecdsa" + "fmt" "math/big" "testing" "time" @@ -182,7 +183,7 @@ func SignMCMSProposal(t *testing.T, env deployment.Environment, proposal *mcmsli } // ExecuteMCMSProposalV2 - Executes an MCMS proposal on a chain. For timelock proposal, use ExecuteMCMSTimelockProposalV2 instead. -func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *mcmslib.Proposal) { +func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *mcmslib.Proposal) error { t.Log("Executing proposal") encoders, err := proposal.GetEncoders() @@ -226,7 +227,9 @@ func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *m for chainSelector := range executorsMap { t.Logf("[ExecuteMCMSProposalV2] Setting root on chain %d...", chainSelector) root, err := executable.SetRoot(env.GetContext(), chainSelector) - require.NoError(t, deployment.MaybeDataErr(err), "[ExecuteMCMSProposalV2] SetRoot failed") + if err != nil { + return fmt.Errorf("[ExecuteMCMSProposalV2] SetRoot failed: %w", err) + } family, err := chainsel.GetSelectorFamily(uint64(chainSelector)) require.NoError(t, err) @@ -237,7 +240,9 @@ func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *m evmTransaction := root.RawTransaction.(*gethtypes.Transaction) t.Logf("[ExecuteMCMSProposalV2] SetRoot EVM tx hash: %s", evmTransaction.Hash().String()) _, err = chain.Confirm(evmTransaction) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSProposalV2] Confirm failed: %w", err) + } } } @@ -245,7 +250,9 @@ func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *m for i, op := range proposal.Operations { t.Logf("[ExecuteMCMSProposalV2] Executing operation index=%d on chain %d...", i, uint64(op.ChainSelector)) result, err := executable.Execute(env.GetContext(), i) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSProposalV2] Execute failed: %w", err) + } family, err := chainsel.GetSelectorFamily(uint64(op.ChainSelector)) require.NoError(t, err) @@ -255,14 +262,18 @@ func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *m evmTransaction := result.RawTransaction.(*gethtypes.Transaction) t.Logf("[ExecuteMCMSProposalV2] Operation %d EVM tx hash: %s", i, evmTransaction.Hash().String()) _, err = chain.Confirm(evmTransaction) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSProposalV2] Confirm failed: %w", err) + } } } + + return nil } // ExecuteMCMSTimelockProposalV2 - Includes an option to set callProxy to execute the calls through a proxy. // If the callProxy is not set, the calls will be executed directly to the timelock. -func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, timelockProposal *mcmslib.TimelockProposal, opts ...mcmslib.Option) { +func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, timelockProposal *mcmslib.TimelockProposal, opts ...mcmslib.Option) error { t.Log("Executing timelock proposal") // build a "chainSelector => executor" map @@ -296,7 +307,9 @@ func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, tim var tx = mcmstypes.TransactionResult{} for i, op := range timelockProposal.Operations { tx, err = timelockExecutable.Execute(env.GetContext(), i, opts...) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSTimelockProposalV2] Execute failed: %w", err) + } family, err := chainsel.GetSelectorFamily(uint64(op.ChainSelector)) require.NoError(t, err) @@ -306,9 +319,13 @@ func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, tim chain := env.Chains[uint64(op.ChainSelector)] evmTransaction := tx.RawTransaction.(*gethtypes.Transaction) _, err = chain.Confirm(evmTransaction) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSTimelockProposalV2] Confirm failed: %w", err) + } } } + + return nil } func SingleGroupTimelockConfig(t *testing.T) commontypes.MCMSWithTimelockConfig { diff --git a/deployment/keystone/changeset/add_capabilities.go b/deployment/keystone/changeset/add_capabilities.go index 7f9639ff870..cb792939858 100644 --- a/deployment/keystone/changeset/add_capabilities.go +++ b/deployment/keystone/changeset/add_capabilities.go @@ -4,9 +4,9 @@ import ( "errors" "fmt" - gethcommon "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" @@ -58,24 +58,33 @@ func AddCapabilities(env deployment.Environment, req *AddCapabilitiesRequest) (d if ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]gethcommon.Address{ - registryChain.Selector: contractSet.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + registryChain.Selector: contractSet.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - registryChain.Selector: contractSet.ProposerMcm, + proposerMCMSes := map[uint64]string{ + registryChain.Selector: contractSet.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]mcmssdk.Inspector{ + req.RegistryChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*ops}, + inspectorPerChain, + []mcmstypes.BatchOperation{*ops}, "proposal to add capabilities", req.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/add_capabilities_test.go b/deployment/keystone/changeset/add_capabilities_test.go index 7175a29f86f..b9aad9e310a 100644 --- a/deployment/keystone/changeset/add_capabilities_test.go +++ b/deployment/keystone/changeset/add_capabilities_test.go @@ -63,7 +63,7 @@ func TestAddCapabilities(t *testing.T) { } csOut, err := changeset.AddCapabilities(te.Env, req) require.NoError(t, err) - require.Len(t, csOut.Proposals, 1) + require.Len(t, csOut.MCMSTimelockProposals, 1) require.Nil(t, csOut.AddressBook) // now apply the changeset such that the proposal is signed and execed diff --git a/deployment/keystone/changeset/add_nodes.go b/deployment/keystone/changeset/add_nodes.go index 1166b5fff27..b5bd7448026 100644 --- a/deployment/keystone/changeset/add_nodes.go +++ b/deployment/keystone/changeset/add_nodes.go @@ -4,9 +4,9 @@ import ( "errors" "fmt" - gethcommon "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -236,20 +236,29 @@ func AddNodes(env deployment.Environment, req *AddNodesRequest) (deployment.Chan // create mcms proposal if needed out := deployment.ChangesetOutput{} if useMCMS { - if resp.Ops == nil || len(resp.Ops.Batch) == 0 { + if resp.Ops == nil || len(resp.Ops.Transactions) == 0 { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]gethcommon.Address{ - registryChain.Selector: registryChainContracts.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + registryChain.Selector: registryChainContracts.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - registryChain.Selector: registryChainContracts.ProposerMcm, + proposerMCMSes := map[uint64]string{ + registryChain.Selector: registryChainContracts.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]mcmssdk.Inspector{ + req.RegistryChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*resp.Ops}, + inspectorPerChain, + []types.BatchOperation{*resp.Ops}, "proposal to add nodes", req.MCMSConfig.MinDuration, ) @@ -257,7 +266,7 @@ func AddNodes(env deployment.Environment, req *AddNodesRequest) (deployment.Chan return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/add_nodes_test.go b/deployment/keystone/changeset/add_nodes_test.go index 75bf8eeacf6..f7a9e120567 100644 --- a/deployment/keystone/changeset/add_nodes_test.go +++ b/deployment/keystone/changeset/add_nodes_test.go @@ -266,8 +266,8 @@ func TestAddNodes(t *testing.T) { tc.checkErr(t, useMCMS, err) return } - require.NotNil(t, r.Proposals) //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field - require.Len(t, r.Proposals, 1) //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field + require.NotNil(t, r.MCMSTimelockProposals) + require.Len(t, r.MCMSTimelockProposals, 1) applyErr := applyProposal( t, tc.input.te, diff --git a/deployment/keystone/changeset/append_node_capabilities.go b/deployment/keystone/changeset/append_node_capabilities.go index 826ba4601f7..fcd20b856ad 100644 --- a/deployment/keystone/changeset/append_node_capabilities.go +++ b/deployment/keystone/changeset/append_node_capabilities.go @@ -4,9 +4,9 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -34,24 +34,33 @@ func AppendNodeCapabilities(env deployment.Environment, req *AppendNodeCapabilit if r.Ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]common.Address{ - c.Chain.Selector: contractSet.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + c.Chain.Selector: contractSet.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - c.Chain.Selector: contractSet.ProposerMcm, + proposerMCMSes := map[uint64]string{ + c.Chain.Selector: contractSet.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]sdk.Inspector{ + req.RegistryChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*r.Ops}, + inspectorPerChain, + []types.BatchOperation{*r.Ops}, "proposal to set update node capabilities", req.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/append_node_capabilities_test.go b/deployment/keystone/changeset/append_node_capabilities_test.go index 3952b0ef158..1c307aa949c 100644 --- a/deployment/keystone/changeset/append_node_capabilities_test.go +++ b/deployment/keystone/changeset/append_node_capabilities_test.go @@ -50,7 +50,7 @@ func TestAppendNodeCapabilities(t *testing.T) { csOut, err := changeset.AppendNodeCapabilities(te.Env, &cfg) require.NoError(t, err) - require.Empty(t, csOut.Proposals) + require.Empty(t, csOut.MCMSTimelockProposals) require.Nil(t, csOut.AddressBook) validateCapabilityAppends(t, te, newCapabilities) @@ -78,9 +78,9 @@ func TestAppendNodeCapabilities(t *testing.T) { csOut, err := changeset.AppendNodeCapabilities(te.Env, &cfg) require.NoError(t, err) - require.Len(t, csOut.Proposals, 1) - require.Len(t, csOut.Proposals[0].Transactions, 1) - require.Len(t, csOut.Proposals[0].Transactions[0].Batch, 2) // add capabilities, update nodes + require.Len(t, csOut.MCMSTimelockProposals, 1) + require.Len(t, csOut.MCMSTimelockProposals[0].Operations, 1) + require.Len(t, csOut.MCMSTimelockProposals[0].Operations[0].Transactions, 2) // add capabilities, update nodes require.Nil(t, csOut.AddressBook) // now apply the changeset such that the proposal is signed and execed diff --git a/deployment/keystone/changeset/deploy_ocr3.go b/deployment/keystone/changeset/deploy_ocr3.go index 75f9b75ecd1..c9da8b81237 100644 --- a/deployment/keystone/changeset/deploy_ocr3.go +++ b/deployment/keystone/changeset/deploy_ocr3.go @@ -7,9 +7,9 @@ import ( "io" "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -92,24 +92,33 @@ func ConfigureOCR3Contract(env deployment.Environment, cfg ConfigureOCR3Config) return out, fmt.Errorf("failed to get contract sets: %w", err) } contracts := r.ContractSets[cfg.ChainSel] - timelocksPerChain := map[uint64]common.Address{ - cfg.ChainSel: contracts.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + cfg.ChainSel: contracts.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - cfg.ChainSel: contracts.ProposerMcm, + proposerMCMSes := map[uint64]string{ + cfg.ChainSel: contracts.ProposerMcm.Address().Hex(), } - proposal, err := proposalutils.BuildProposalFromBatches( + inspector, err := proposalutils.McmsInspectorForChain(env, cfg.ChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]sdk.Inspector{ + cfg.ChainSel: inspector, + } + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*resp.Ops}, + inspectorPerChain, + []mcmstypes.BatchOperation{*resp.Ops}, "proposal to set OCR3 config", cfg.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/deploy_ocr3_test.go b/deployment/keystone/changeset/deploy_ocr3_test.go index b8fa43e9076..b9d2d034997 100644 --- a/deployment/keystone/changeset/deploy_ocr3_test.go +++ b/deployment/keystone/changeset/deploy_ocr3_test.go @@ -11,6 +11,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" @@ -81,7 +82,7 @@ func TestConfigureOCR3(t *testing.T) { require.NoError(t, err) assert.Len(t, got.Signers, 4) assert.Len(t, got.Transmitters, 4) - assert.Nil(t, csOut.Proposals) + assert.Nil(t, csOut.MCMSTimelockProposals) }) t.Run("success multiple OCR3 contracts", func(t *testing.T) { @@ -146,7 +147,7 @@ func TestConfigureOCR3(t *testing.T) { require.NoError(t, err) assert.Len(t, got.Signers, 4) assert.Len(t, got.Transmitters, 4) - assert.Nil(t, csOut.Proposals) + assert.Nil(t, csOut.MCMSTimelockProposals) }) t.Run("fails multiple OCR3 contracts but unspecified address", func(t *testing.T) { @@ -258,8 +259,8 @@ func TestConfigureOCR3(t *testing.T) { require.NoError(t, err) assert.Len(t, got.Signers, 4) assert.Len(t, got.Transmitters, 4) - assert.NotNil(t, csOut.Proposals) - t.Logf("got: %v", csOut.Proposals[0]) + assert.NotNil(t, csOut.MCMSTimelockProposals) + t.Logf("got: %v", csOut.MCMSTimelockProposals[0]) contracts := te.ContractSets()[te.RegistrySelector] require.NoError(t, err) diff --git a/deployment/keystone/changeset/internal/capability_management.go b/deployment/keystone/changeset/internal/capability_management.go index 47f211fdcef..8f14dbc1b24 100644 --- a/deployment/keystone/changeset/internal/capability_management.go +++ b/deployment/keystone/changeset/internal/capability_management.go @@ -4,18 +4,19 @@ import ( "fmt" "math/big" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" ) // AddCapabilities adds the capabilities to the registry // // It is idempotent. It deduplicates the input capabilities. -func AddCapabilities(lggr logger.Logger, registry *kcr.CapabilitiesRegistry, chain deployment.Chain, capabilities []kcr.CapabilitiesRegistryCapability, useMCMS bool) (*timelock.BatchChainOperation, error) { +func AddCapabilities(lggr logger.Logger, registry *kcr.CapabilitiesRegistry, chain deployment.Chain, capabilities []kcr.CapabilitiesRegistryCapability, useMCMS bool) (*mcmstypes.BatchOperation, error) { if len(capabilities) == 0 { return nil, nil } @@ -43,23 +44,19 @@ func AddCapabilities(lggr logger.Logger, registry *kcr.CapabilitiesRegistry, cha return nil, nil } -func addCapabilitiesMCMSProposal(registry *kcr.CapabilitiesRegistry, caps []kcr.CapabilitiesRegistryCapability, regChain deployment.Chain) (*timelock.BatchChainOperation, error) { +func addCapabilitiesMCMSProposal(registry *kcr.CapabilitiesRegistry, caps []kcr.CapabilitiesRegistryCapability, regChain deployment.Chain) (*mcmstypes.BatchOperation, error) { tx, err := registry.AddCapabilities(deployment.SimTransactOpts(), caps) if err != nil { err = deployment.DecodeErr(kcr.CapabilitiesRegistryABI, err) return nil, fmt.Errorf("failed to call AddNodeOperators: %w", err) } - return &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(regChain.Selector), - Batch: []mcms.Operation{ - { - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }, nil + ops, err := proposalutils.BatchOperationForChain(regChain.Selector, registry.Address().Hex(), tx.Data(), big.NewInt(0), string(CapabilitiesRegistry), nil) + if err != nil { + return nil, fmt.Errorf("failed to create batch operation: %w", err) + } + + return &ops, nil } // CapabilityID returns a unique id for the capability diff --git a/deployment/keystone/changeset/internal/deploy.go b/deployment/keystone/changeset/internal/deploy.go index 5abb33dc3a4..c8183182c3e 100644 --- a/deployment/keystone/changeset/internal/deploy.go +++ b/deployment/keystone/changeset/internal/deploy.go @@ -18,6 +18,7 @@ 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" + mcmstypes "github.com/smartcontractkit/mcms/types" "golang.org/x/exp/maps" "google.golang.org/protobuf/proto" @@ -25,6 +26,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" 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" ) @@ -337,7 +339,7 @@ func ConfigureOCR3Contract(env *deployment.Environment, chainSel uint64, dons [] type ConfigureOCR3Resp struct { OCR2OracleConfig - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } type ConfigureOCR3Config struct { @@ -544,9 +546,10 @@ type RegisterNodesRequest struct { Nops []*capabilities_registry.CapabilitiesRegistryNodeOperatorAdded UseMCMS bool } + type RegisterNodesResponse struct { nodeIDToParams map[string]capabilities_registry.CapabilitiesRegistryNodeParams - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } // registerNodes registers the nodes with the registry. it assumes that the deployer key in the Chain @@ -679,8 +682,9 @@ type AddNodesResponse struct { // It may be empty if no nodes were added AddedNodes []capabilities_registry.CapabilitiesRegistryNodeParams // Ops is only populated if UseMCMS is true - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } + type AddNodesRequest struct { RegistryChain deployment.Chain CapabilitiesRegistry *capabilities_registry.CapabilitiesRegistry @@ -771,23 +775,19 @@ func getNodesToRegister( } // addNodesMCMSProposal generates a single call to AddNodes for all the node params at once. -func addNodesMCMSProposal(registry *capabilities_registry.CapabilitiesRegistry, params []capabilities_registry.CapabilitiesRegistryNodeParams, regChainSel uint64) (*timelock.BatchChainOperation, error) { +func addNodesMCMSProposal(registry *capabilities_registry.CapabilitiesRegistry, params []capabilities_registry.CapabilitiesRegistryNodeParams, regChainSel uint64) (*mcmstypes.BatchOperation, error) { tx, err := registry.AddNodes(deployment.SimTransactOpts(), params) if err != nil { err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err) return nil, fmt.Errorf("failed to simulate call to AddNodes: %w", err) } - return &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(regChainSel), - Batch: []mcms.Operation{ - { - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }, nil + ops, err := proposalutils.BatchOperationForChain(regChainSel, registry.Address().Hex(), tx.Data(), big.NewInt(0), string(CapabilitiesRegistry), nil) + if err != nil { + return nil, fmt.Errorf("failed to create batch operation: %w", err) + } + + return &ops, nil } type DONToRegister struct { @@ -808,7 +808,7 @@ type RegisterDonsRequest struct { type RegisterDonsResponse struct { DonInfos map[string]capabilities_registry.CapabilitiesRegistryDONInfo - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } func sortedHash(p2pids [][32]byte) string { @@ -844,7 +844,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) + mcmsOps := make([]mcmstypes.Transaction, 0) for _, don := range req.DonsToRegister { var p2pIds [][32]byte for _, n := range don.Nodes { @@ -905,10 +905,9 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes if req.UseMCMS { lggr.Debugw("adding mcms op for DON", "don", don.Name) - op := mcms.Operation{ - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), + op, err := proposalutils.TransactionForChain(req.RegistryChainSelector, registry.Address().Hex(), tx.Data(), big.NewInt(0), "", nil) + if err != nil { + return nil, fmt.Errorf("failed to create transaction for chain %d: %w", req.RegistryChainSelector, err) } mcmsOps = append(mcmsOps, op) continue @@ -925,9 +924,9 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes if req.UseMCMS { if len(mcmsOps) > 0 { return &RegisterDonsResponse{ - Ops: &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(registryChain.Selector), - Batch: mcmsOps, + Ops: &mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(registryChain.Selector), + Transactions: mcmsOps, }, }, nil } diff --git a/deployment/keystone/changeset/internal/deploy_test.go b/deployment/keystone/changeset/internal/deploy_test.go index 96fd0c3ef2a..41c1a793d4e 100644 --- a/deployment/keystone/changeset/internal/deploy_test.go +++ b/deployment/keystone/changeset/internal/deploy_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "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/test" @@ -88,7 +89,7 @@ func Test_AddCapabilities(t *testing.T) { ops, err := internal.AddCapabilities(lggr, registry, chain, capabilities, useMCMS) require.NoError(t, err) require.NotNil(t, ops) - require.Len(t, ops.Batch, 1) + require.Len(t, ops.Transactions, 1) }) t.Run("does nothing if no capabilities", func(t *testing.T) { @@ -284,7 +285,7 @@ func Test_RegisterNodes(t *testing.T) { require.NoError(t, err) if tc.useMCMS { require.NotNil(t, resp.Ops) - require.Len(t, resp.Ops.Batch, tc.want.nOps) + require.Len(t, resp.Ops.Transactions, tc.want.nOps) } else { assertNodesExist(t, registry, tc.want.nodes...) } @@ -419,7 +420,7 @@ func Test_RegisterDons(t *testing.T) { }) require.NoError(t, err) require.NotNil(t, resp.Ops) - require.Len(t, resp.Ops.Batch, 1) + require.Len(t, resp.Ops.Transactions, 1) }) t.Run("no new dons to add results in no mcms ops", func(t *testing.T) { @@ -551,7 +552,7 @@ func Test_RegisterDons(t *testing.T) { }) require.NoError(t, err) require.NotNil(t, resp.Ops) - require.Len(t, resp.Ops.Batch, 2) + require.Len(t, resp.Ops.Transactions, 2) }) } diff --git a/deployment/keystone/changeset/internal/ocr3config.go b/deployment/keystone/changeset/internal/ocr3config.go index ef5bd9bda2e..e8038134f02 100644 --- a/deployment/keystone/changeset/internal/ocr3config.go +++ b/deployment/keystone/changeset/internal/ocr3config.go @@ -13,15 +13,14 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" - "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" kocr3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/ocr3_capability_1_0_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" @@ -301,7 +300,7 @@ func (r configureOCR3Request) generateOCR3Config() (OCR2OracleConfig, error) { type configureOCR3Response struct { ocrConfig OCR2OracleConfig - ops *timelock.BatchChainOperation + ops *mcmstypes.BatchOperation } func configureOCR3contract(req configureOCR3Request) (*configureOCR3Response, error) { @@ -334,7 +333,7 @@ func configureOCR3contract(req configureOCR3Request) (*configureOCR3Response, er return nil, fmt.Errorf("failed to call SetConfig for OCR3 contract %s using mcms: %T: %w", req.contract.Address().String(), req.useMCMS, err) } - var ops *timelock.BatchChainOperation + var ops mcmstypes.BatchOperation if !req.useMCMS { _, err = req.chain.Confirm(tx) if err != nil { @@ -342,17 +341,11 @@ func configureOCR3contract(req configureOCR3Request) (*configureOCR3Response, er return nil, fmt.Errorf("failed to confirm SetConfig for OCR3 contract %s: %w", req.contract.Address().String(), err) } } else { - ops = &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(req.chain.Selector), - Batch: []mcms.Operation{ - { - To: req.contract.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, + ops, err = proposalutils.BatchOperationForChain(req.chain.Selector, req.contract.Address().Hex(), tx.Data(), big.NewInt(0), string(OCR3Capability), nil) + if err != nil { + return nil, fmt.Errorf("failed to create batch operation: %w", err) } } - return &configureOCR3Response{ocrConfig, ops}, nil + return &configureOCR3Response{ocrConfig, &ops}, nil } diff --git a/deployment/keystone/changeset/internal/update_don.go b/deployment/keystone/changeset/internal/update_don.go index 92529a939dd..fb7702fc43f 100644 --- a/deployment/keystone/changeset/internal/update_don.go +++ b/deployment/keystone/changeset/internal/update_don.go @@ -11,13 +11,12 @@ import ( "sort" "github.com/ethereum/go-ethereum/accounts/abi/bind" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" 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" ) @@ -68,7 +67,7 @@ func (r *UpdateDonRequest) Validate() error { type UpdateDonResponse struct { DonInfo kcr.CapabilitiesRegistryDONInfo - Ops *timelock.BatchChainOperation + Ops *types.BatchOperation } func UpdateDon(_ logger.Logger, req *UpdateDonRequest) (*UpdateDonResponse, error) { @@ -108,28 +107,22 @@ func UpdateDon(_ logger.Logger, req *UpdateDonRequest) (*UpdateDonResponse, erro err = deployment.DecodeErr(kcr.CapabilitiesRegistryABI, err) return nil, fmt.Errorf("failed to call UpdateDON: %w", err) } - var ops *timelock.BatchChainOperation + var ops types.BatchOperation if !req.UseMCMS { _, err = req.Chain.Confirm(tx) if err != nil { return nil, fmt.Errorf("failed to confirm UpdateDON transaction %s: %w", tx.Hash().String(), err) } } else { - ops = &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(req.Chain.Selector), - Batch: []mcms.Operation{ - { - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, + ops, err = proposalutils.BatchOperationForChain(req.Chain.Selector, registry.Address().Hex(), tx.Data(), big.NewInt(0), string(CapabilitiesRegistry), nil) + if err != nil { + return nil, fmt.Errorf("failed to create batch operation: %w", err) } } out := don out.CapabilityConfigurations = cfgs - return &UpdateDonResponse{DonInfo: out, Ops: ops}, nil + return &UpdateDonResponse{DonInfo: out, Ops: &ops}, nil } func PeerIDsToBytes(p2pIDs []p2pkey.PeerID) [][32]byte { diff --git a/deployment/keystone/changeset/internal/update_nodes.go b/deployment/keystone/changeset/internal/update_nodes.go index 4c33b3d08a3..2c496a13158 100644 --- a/deployment/keystone/changeset/internal/update_nodes.go +++ b/deployment/keystone/changeset/internal/update_nodes.go @@ -9,11 +9,11 @@ import ( "sort" "github.com/ethereum/go-ethereum/accounts/abi/bind" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" 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" @@ -37,7 +37,7 @@ type UpdateNodesRequest struct { UseMCMS bool // If UseMCMS is true, and Ops is not nil then the UpdateNodes contract operation // will be added to the Ops.Batch - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } func (req *UpdateNodesRequest) NodeParams() ([]kcr.CapabilitiesRegistryNodeParams, error) { @@ -90,7 +90,7 @@ type UpdateNodesResponse struct { NodeParams []kcr.CapabilitiesRegistryNodeParams // MCMS operation to update the nodes // The operation is added to the Batch of the given Ops if not nil - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } // UpdateNodes updates the nodes in the registry @@ -124,21 +124,20 @@ func UpdateNodes(lggr logger.Logger, req *UpdateNodesRequest) (*UpdateNodesRespo return nil, fmt.Errorf("failed to confirm UpdateNodes confirm transaction %s: %w", tx.Hash().String(), err) } } else { - op := mcms.Operation{ - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), + transaction, err := proposalutils.TransactionForChain(req.Chain.Selector, registry.Address().Hex(), tx.Data(), big.NewInt(0), "", nil) + if err != nil { + return nil, err } if ops == nil { - ops = &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(req.Chain.Selector), - Batch: []mcms.Operation{ - op, + ops = &mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(req.Chain.Selector), + Transactions: []mcmstypes.Transaction{ + transaction, }, } } else { - ops.Batch = append(ops.Batch, op) + ops.Transactions = append(ops.Transactions, transaction) } } diff --git a/deployment/keystone/changeset/update_don.go b/deployment/keystone/changeset/update_don.go index 6f168bb55d6..7d02db0eda0 100644 --- a/deployment/keystone/changeset/update_don.go +++ b/deployment/keystone/changeset/update_don.go @@ -66,16 +66,16 @@ func UpdateDon(env deployment.Environment, req *UpdateDonRequest) (deployment.Ch if updateResult.Ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - if len(appendResult.Proposals) == 0 { + if len(appendResult.MCMSTimelockProposals) == 0 { return out, errors.New("expected append node capabilities to return proposals") } - out.Proposals = appendResult.Proposals + out.MCMSTimelockProposals = appendResult.MCMSTimelockProposals // add the update don to the existing batch // this makes the proposal all-or-nothing because all the operations are in the same batch, there is only one tr // transaction and only one proposal - out.Proposals[0].Transactions[0].Batch = append(out.Proposals[0].Transactions[0].Batch, updateResult.Ops.Batch...) + out.MCMSTimelockProposals[0].Operations[0].Transactions = append(out.MCMSTimelockProposals[0].Operations[0].Transactions, updateResult.Ops.Transactions...) } return out, nil } diff --git a/deployment/keystone/changeset/update_don_test.go b/deployment/keystone/changeset/update_don_test.go index ca037c45058..c567da56551 100644 --- a/deployment/keystone/changeset/update_don_test.go +++ b/deployment/keystone/changeset/update_don_test.go @@ -129,8 +129,8 @@ func TestUpdateDon(t *testing.T) { tc.checkErr(t, useMCMS, err) return } - require.NotNil(t, csOut.Proposals) //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field - require.Len(t, csOut.Proposals, 1) //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field + require.NotNil(t, csOut.MCMSTimelockProposals) + require.Len(t, csOut.MCMSTimelockProposals, 1) applyErr := applyProposal(t, te, commonchangeset.Configure( deployment.CreateLegacyChangeSet(changeset.UpdateDon), &cfg, diff --git a/deployment/keystone/changeset/update_node_capabilities.go b/deployment/keystone/changeset/update_node_capabilities.go index bf869416604..38cd8b6dfb5 100644 --- a/deployment/keystone/changeset/update_node_capabilities.go +++ b/deployment/keystone/changeset/update_node_capabilities.go @@ -5,11 +5,10 @@ import ( "fmt" "strconv" - "github.com/ethereum/go-ethereum/common" chainsel "github.com/smartcontractkit/chain-selectors" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -123,24 +122,32 @@ func UpdateNodeCapabilities(env deployment.Environment, req *UpdateNodeCapabilit if r.Ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]common.Address{ - c.Chain.Selector: contractSet.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + c.Chain.Selector: contractSet.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - c.Chain.Selector: contractSet.ProposerMcm, + proposerMCMSes := map[uint64]string{ + c.Chain.Selector: contractSet.ProposerMcm.Address().Hex(), } - - proposal, err := proposalutils.BuildProposalFromBatches( + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]mcmssdk.Inspector{ + req.RegistryChainSel: inspector, + } + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*r.Ops}, + inspectorPerChain, + []types.BatchOperation{*r.Ops}, "proposal to set update node capabilities", req.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/update_node_capabilities_test.go b/deployment/keystone/changeset/update_node_capabilities_test.go index b96f32f716d..60b5508ff18 100644 --- a/deployment/keystone/changeset/update_node_capabilities_test.go +++ b/deployment/keystone/changeset/update_node_capabilities_test.go @@ -69,7 +69,7 @@ func TestUpdateNodeCapabilities(t *testing.T) { csOut, err := changeset.UpdateNodeCapabilities(te.Env, &cfg) require.NoError(t, err) - require.Empty(t, csOut.Proposals) + require.Empty(t, csOut.MCMSTimelockProposals) require.Nil(t, csOut.AddressBook) validateCapabilityUpdates(t, te, capabiltiesToSet) @@ -106,9 +106,9 @@ func TestUpdateNodeCapabilities(t *testing.T) { csOut, err := changeset.UpdateNodeCapabilities(te.Env, &cfg) require.NoError(t, err) - require.Len(t, csOut.Proposals, 1) - require.Len(t, csOut.Proposals[0].Transactions, 1) - require.Len(t, csOut.Proposals[0].Transactions[0].Batch, 2) // add capabilities, update nodes + require.Len(t, csOut.MCMSTimelockProposals, 1) + require.Len(t, csOut.MCMSTimelockProposals[0].Operations, 1) + require.Len(t, csOut.MCMSTimelockProposals[0].Operations[0].Transactions, 2) // add capabilities, update nodes require.Nil(t, csOut.AddressBook) // now apply the changeset such that the proposal is signed and execed diff --git a/deployment/keystone/changeset/update_nodes.go b/deployment/keystone/changeset/update_nodes.go index cc7c1c08eb7..a09a2b86ced 100644 --- a/deployment/keystone/changeset/update_nodes.go +++ b/deployment/keystone/changeset/update_nodes.go @@ -5,10 +5,10 @@ import ( "fmt" "time" - "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/mcms" + "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -55,7 +55,7 @@ func (r UpdateNodesRequest) UseMCMS() bool { type NodeUpdate = internal.NodeUpdate -// UpdateNodes updates the a set of nodes. +// UpdateNodes updates a set of nodes. // The nodes and capabilities in the request must already exist in the registry contract. func UpdateNodes(env deployment.Environment, req *UpdateNodesRequest) (deployment.ChangesetOutput, error) { // extract the registry contract and chain from the environment @@ -90,24 +90,33 @@ func UpdateNodes(env deployment.Environment, req *UpdateNodesRequest) (deploymen if resp.Ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]common.Address{ - req.RegistryChainSel: contracts.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + req.RegistryChainSel: contracts.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - req.RegistryChainSel: contracts.ProposerMcm, + proposerMCMSes := map[uint64]string{ + req.RegistryChainSel: contracts.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]sdk.Inspector{ + req.RegistryChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*resp.Ops}, + inspectorPerChain, + []types.BatchOperation{*resp.Ops}, "proposal to set update nodes", req.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil diff --git a/deployment/keystone/changeset/update_nodes_test.go b/deployment/keystone/changeset/update_nodes_test.go index aa921821b84..1117bd8da65 100644 --- a/deployment/keystone/changeset/update_nodes_test.go +++ b/deployment/keystone/changeset/update_nodes_test.go @@ -82,7 +82,7 @@ func TestUpdateNodes(t *testing.T) { csOut, err := changeset.UpdateNodes(te.Env, &cfg) require.NoError(t, err) - require.Len(t, csOut.Proposals, 1) + require.Len(t, csOut.MCMSTimelockProposals, 1) require.Nil(t, csOut.AddressBook) // now apply the changeset such that the proposal is signed and execed diff --git a/deployment/keystone/changeset/workflowregistry/strategies.go b/deployment/keystone/changeset/workflowregistry/strategies.go index 617d6e6e8dc..22acf46c9cb 100644 --- a/deployment/keystone/changeset/workflowregistry/strategies.go +++ b/deployment/keystone/changeset/workflowregistry/strategies.go @@ -6,10 +6,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + mcmslib "github.com/smartcontractkit/mcms" + "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -40,6 +39,7 @@ type mcmsTransaction struct { Address common.Address ChainSel uint64 ContractSet *changeset.ContractSet + Env deployment.Environment } func (m *mcmsTransaction) Apply(callFn func(opts *bind.TransactOpts) (*types.Transaction, error)) (deployment.ChangesetOutput, error) { @@ -50,28 +50,35 @@ func (m *mcmsTransaction) Apply(callFn func(opts *bind.TransactOpts) (*types.Tra return deployment.ChangesetOutput{}, err } - op := timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(m.ChainSel), - Batch: []mcms.Operation{ - { - Data: tx.Data(), - To: m.Address, - Value: big.NewInt(0), - }, - }, + transaction, err := proposalutils.TransactionForChain(m.ChainSel, m.Address.Hex(), tx.Data(), big.NewInt(0), "", nil) + if err != nil { + return deployment.ChangesetOutput{}, err + } + op := mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(m.ChainSel), + Transactions: []mcmstypes.Transaction{transaction}, } - timelocksPerChain := map[uint64]common.Address{ - m.ChainSel: m.ContractSet.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + m.ChainSel: m.ContractSet.Timelock.Address().Hex(), + } + proposerMCMSes := map[uint64]string{ + m.ChainSel: m.ContractSet.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(m.Env, m.ChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - m.ChainSel: m.ContractSet.ProposerMcm, + inspectorPerChain := map[uint64]sdk.Inspector{ + m.ChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + m.Env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{op}, + inspectorPerChain, + []mcmstypes.BatchOperation{op}, m.Description, m.Config.MinDuration, ) @@ -80,6 +87,6 @@ func (m *mcmsTransaction) Apply(callFn func(opts *bind.TransactOpts) (*types.Tra } return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*proposal}, + MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}, }, nil } diff --git a/deployment/keystone/changeset/workflowregistry/update_allowed_dons.go b/deployment/keystone/changeset/workflowregistry/update_allowed_dons.go index 5001370b552..8295a140f87 100644 --- a/deployment/keystone/changeset/workflowregistry/update_allowed_dons.go +++ b/deployment/keystone/changeset/workflowregistry/update_allowed_dons.go @@ -63,6 +63,7 @@ func UpdateAllowedDons(env deployment.Environment, req *UpdateAllowedDonsRequest Address: registry.Address(), ChainSel: req.RegistryChainSel, ContractSet: &cs, + Env: env, } } else { s = &simpleTransaction{ diff --git a/deployment/keystone/changeset/workflowregistry/update_allowed_dons_test.go b/deployment/keystone/changeset/workflowregistry/update_allowed_dons_test.go index dfac7e418a3..15231780478 100644 --- a/deployment/keystone/changeset/workflowregistry/update_allowed_dons_test.go +++ b/deployment/keystone/changeset/workflowregistry/update_allowed_dons_test.go @@ -89,7 +89,7 @@ func Test_UpdateAllowedDons_WithMCMS(t *testing.T) { out, err := workflowregistry.UpdateAllowedDons(te.Env, req) require.NoError(t, err) - require.Len(t, out.Proposals, 1) + require.Len(t, out.MCMSTimelockProposals, 1) require.Nil(t, out.AddressBook) contracts := te.ContractSets()[te.RegistrySelector] diff --git a/deployment/keystone/changeset/workflowregistry/update_authorized_addresses.go b/deployment/keystone/changeset/workflowregistry/update_authorized_addresses.go index b2d5ffcce1e..bfab247a165 100644 --- a/deployment/keystone/changeset/workflowregistry/update_authorized_addresses.go +++ b/deployment/keystone/changeset/workflowregistry/update_authorized_addresses.go @@ -88,6 +88,7 @@ func UpdateAuthorizedAddresses(env deployment.Environment, req *UpdateAuthorized Address: registry.Address(), ChainSel: chain.Selector, ContractSet: &cs, + Env: env, } } else { s = &simpleTransaction{ diff --git a/deployment/keystone/changeset/workflowregistry/update_authorized_addresses_test.go b/deployment/keystone/changeset/workflowregistry/update_authorized_addresses_test.go index 694e59811bd..41a4064c82a 100644 --- a/deployment/keystone/changeset/workflowregistry/update_authorized_addresses_test.go +++ b/deployment/keystone/changeset/workflowregistry/update_authorized_addresses_test.go @@ -92,7 +92,7 @@ func Test_UpdateAuthorizedAddresses_WithMCMS(t *testing.T) { out, err := workflowregistry.UpdateAuthorizedAddresses(te.Env, req) require.NoError(t, err) - require.Len(t, out.Proposals, 1) + require.Len(t, out.MCMSTimelockProposals, 1) require.Nil(t, out.AddressBook) contracts := te.ContractSets()[te.RegistrySelector]