diff --git a/deployment/ccip/changeset/cs_ccip_home.go b/deployment/ccip/changeset/cs_ccip_home.go index 84d70d6f6f0..f91da52590f 100644 --- a/deployment/ccip/changeset/cs_ccip_home.go +++ b/deployment/ccip/changeset/cs_ccip_home.go @@ -10,11 +10,13 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "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" "golang.org/x/exp/maps" + mcmslib "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + mcmsevmsdk "github.com/smartcontractkit/mcms/sdk/evm" + mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" @@ -388,7 +390,7 @@ func PromoteCandidateChangeset( homeChain := e.Chains[cfg.HomeChainSelector] - var ops []mcms.Operation + var mcmsTxs []mcmstypes.Transaction for _, plugin := range cfg.PluginInfo { for _, donID := range donIDs { promoteCandidateOps, err := promoteCandidateForChainOps( @@ -403,9 +405,9 @@ func PromoteCandidateChangeset( cfg.MCMS != nil, ) if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("generating promote candidate ops: %w", err) + return deployment.ChangesetOutput{}, fmt.Errorf("generating promote candidate mcms txs: %w", err) } - ops = append(ops, promoteCandidateOps) + mcmsTxs = append(mcmsTxs, promoteCandidateOps) } } @@ -414,28 +416,25 @@ func PromoteCandidateChangeset( return deployment.ChangesetOutput{}, nil } - prop, err := proposalutils.BuildProposalFromBatches( - map[uint64]common.Address{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address(), - }, - map[uint64]*gethwrappers.ManyChainMultiSig{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm, - }, - []timelock.BatchChainOperation{{ - ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: ops, - }}, + timelocks := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address().Hex()} + proposers := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm.Address().Hex()} + inspectors := map[uint64]mcmssdk.Inspector{cfg.HomeChainSelector: mcmsevmsdk.NewInspector(e.Chains[cfg.HomeChainSelector].Client)} + batches := []mcmstypes.BatchOperation{{ChainSelector: mcmstypes.ChainSelector(cfg.HomeChainSelector), Transactions: mcmsTxs}} + + prop, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposers, + inspectors, + batches, "promoteCandidate", cfg.MCMS.MinDelay, ) if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{ - *prop, - }, - }, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*prop}}, nil } type SetCandidatePluginInfo struct { @@ -615,7 +614,7 @@ func AddDonAndSetCandidateChangeset( if cfg.MCMS != nil { txOpts = deployment.SimTransactOpts() } - var donOps []mcms.Operation + var donMcmsTxs []mcmstypes.Transaction for chainSelector, params := range cfg.PluginInfo.OCRConfigPerRemoteChainSelector { offRampAddress, err := state.GetOffRampAddress(chainSelector) if err != nil { @@ -660,23 +659,23 @@ func AddDonAndSetCandidateChangeset( if err != nil { return deployment.ChangesetOutput{}, err } - donOps = append(donOps, addDonOp) + donMcmsTxs = append(donMcmsTxs, addDonOp) } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - prop, err := proposalutils.BuildProposalFromBatches( - map[uint64]common.Address{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address(), - }, - map[uint64]*gethwrappers.ManyChainMultiSig{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm, - }, - []timelock.BatchChainOperation{{ - ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: donOps, - }}, + timelocks := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address().Hex()} + proposers := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm.Address().Hex()} + inspectors := map[uint64]mcmssdk.Inspector{cfg.HomeChainSelector: mcmsevmsdk.NewInspector(e.Chains[cfg.HomeChainSelector].Client)} + batches := []mcmstypes.BatchOperation{{ChainSelector: mcmstypes.ChainSelector(cfg.HomeChainSelector), Transactions: donMcmsTxs}} + + prop, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposers, + inspectors, + batches, "addDON on new Chain && setCandidate for plugin "+cfg.PluginInfo.PluginType.String(), cfg.MCMS.MinDelay, ) @@ -684,9 +683,7 @@ func AddDonAndSetCandidateChangeset( return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal from batch: %w", err) } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*prop}, - }, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*prop}}, nil } // newDonWithCandidateOp sets the candidate commit config by calling setCandidate on CCIPHome contract through the AddDON call on CapReg contract @@ -700,7 +697,7 @@ func newDonWithCandidateOp( capReg *capabilities_registry.CapabilitiesRegistry, nodes deployment.Nodes, mcmsEnabled bool, -) (mcms.Operation, error) { +) (mcmstypes.Transaction, error) { encodedSetCandidateCall, err := internal.CCIPHomeABI.Pack( "setCandidate", donID, @@ -709,7 +706,7 @@ func newDonWithCandidateOp( [32]byte{}, ) if err != nil { - return mcms.Operation{}, fmt.Errorf("pack set candidate call: %w", err) + return mcmstypes.Transaction{}, fmt.Errorf("pack set candidate call: %w", err) } addDonTx, err := capReg.AddDON( @@ -725,22 +722,27 @@ func newDonWithCandidateOp( false, // acceptsWorkflows nodes.DefaultF(), ) + if err != nil { + return mcmstypes.Transaction{}, fmt.Errorf("failed to call AddDON (ptype: %s): %w", + types.PluginType(pluginConfig.PluginType).String(), err) + } + if !mcmsEnabled { _, err = deployment.ConfirmIfNoErrorWithABI( homeChain, addDonTx, ccip_home.CCIPHomeABI, err) if err != nil { - return mcms.Operation{}, fmt.Errorf("error confirming addDon call: %w", err) + return mcmstypes.Transaction{}, fmt.Errorf("error confirming addDon call: %w", err) } } + + tx, err := proposalutils.TransactionForChain(homeChain.Selector, capReg.Address().Hex(), addDonTx.Data(), + big.NewInt(0), string(CapabilitiesRegistry), []string{}) if err != nil { - return mcms.Operation{}, fmt.Errorf("could not generate add don tx w/ %s config: %w", - types.PluginType(pluginConfig.PluginType).String(), err) + return mcmstypes.Transaction{}, fmt.Errorf("failed to create AddDON mcms tx (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginConfig.PluginType).String(), err) } - return mcms.Operation{ - To: capReg.Address(), - Data: addDonTx.Data(), - Value: big.NewInt(0), - }, nil + + return tx, nil } type SetCandidateChangesetConfig struct { @@ -804,7 +806,7 @@ func SetCandidateChangeset( if cfg.MCMS != nil { txOpts = deployment.SimTransactOpts() } - var setCandidateOps []mcms.Operation + var setCandidateMcmsTxs []mcmstypes.Transaction pluginInfos := make([]string, 0) for _, plugin := range cfg.PluginInfo { pluginInfos = append(pluginInfos, plugin.String()) @@ -845,35 +847,32 @@ func SetCandidateChangeset( if err != nil { return deployment.ChangesetOutput{}, err } - setCandidateOps = append(setCandidateOps, setCandidateMCMSOps...) + setCandidateMcmsTxs = append(setCandidateMcmsTxs, setCandidateMCMSOps...) } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - prop, err := proposalutils.BuildProposalFromBatches( - map[uint64]common.Address{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address(), - }, - map[uint64]*gethwrappers.ManyChainMultiSig{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm, - }, - []timelock.BatchChainOperation{{ - ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: setCandidateOps, - }}, + timelocks := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address().Hex()} + proposers := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm.Address().Hex()} + inspectors := map[uint64]mcmssdk.Inspector{cfg.HomeChainSelector: mcmsevmsdk.NewInspector(e.Chains[cfg.HomeChainSelector].Client)} + batches := []mcmstypes.BatchOperation{{ChainSelector: mcmstypes.ChainSelector(cfg.HomeChainSelector), Transactions: setCandidateMcmsTxs}} + + prop, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposers, + inspectors, + batches, fmt.Sprintf("SetCandidate for plugin details %v", pluginInfos), cfg.MCMS.MinDelay, ) if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{ - *prop, - }, - }, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*prop}}, nil } // setCandidateOnExistingDon calls setCandidate on CCIPHome contract through the UpdateDON call on CapReg contract @@ -886,7 +885,7 @@ func setCandidateOnExistingDon( donID uint32, pluginConfig ccip_home.CCIPHomeOCR3Config, mcmsEnabled bool, -) ([]mcms.Operation, error) { +) ([]mcmstypes.Transaction, error) { if donID == 0 { return nil, errors.New("donID is zero") } @@ -916,21 +915,27 @@ func setCandidateOnExistingDon( false, nodes.DefaultF(), ) + if err != nil { + return nil, fmt.Errorf("failed to call UpdateDON in set candidate (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginConfig.PluginType).String(), err) + } + if !mcmsEnabled { _, err = deployment.ConfirmIfNoErrorWithABI( homeChain, updateDonTx, ccip_home.CCIPHomeABI, err) if err != nil { - return nil, fmt.Errorf("error confirming updateDon call: %w", err) + return nil, fmt.Errorf("error confirming UpdateDON call in set candidate (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginConfig.PluginType).String(), err) } } + + tx, err := proposalutils.TransactionForChain(homeChain.Selector, capReg.Address().Hex(), updateDonTx.Data(), big.NewInt(0), string(CapabilitiesRegistry), []string{}) if err != nil { - return nil, fmt.Errorf("update don w/ setCandidate call: %w", err) + return nil, fmt.Errorf("failed to create UpdateDON mcms tx in set candidate (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginConfig.PluginType).String(), err) } - return []mcms.Operation{{ - To: capReg.Address(), - Data: updateDonTx.Data(), - Value: big.NewInt(0), - }}, nil + + return []mcmstypes.Transaction{tx}, nil } // promoteCandidateOp will create the MCMS Operation for `promoteCandidateAndRevokeActive` directed towards the capabilityRegistry @@ -943,10 +948,10 @@ func promoteCandidateOp( donID uint32, pluginType uint8, mcmsEnabled bool, -) (mcms.Operation, error) { +) (mcmstypes.Transaction, error) { allConfigs, err := ccipHome.GetAllConfigs(nil, donID, pluginType) if err != nil { - return mcms.Operation{}, err + return mcmstypes.Transaction{}, err } encodedPromotionCall, err := internal.CCIPHomeABI.Pack( @@ -957,7 +962,7 @@ func promoteCandidateOp( allConfigs.ActiveConfig.ConfigDigest, ) if err != nil { - return mcms.Operation{}, fmt.Errorf("pack promotion call: %w", err) + return mcmstypes.Transaction{}, fmt.Errorf("pack promotion call: %w", err) } updateDonTx, err := capReg.UpdateDON( @@ -973,23 +978,28 @@ func promoteCandidateOp( false, nodes.DefaultF(), ) + if err != nil { + return mcmstypes.Transaction{}, fmt.Errorf("failed to call UpdateDON in promote candidate (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginType).String(), err) + } + if !mcmsEnabled { _, err = deployment.ConfirmIfNoErrorWithABI( homeChain, updateDonTx, ccip_home.CCIPHomeABI, err) if err != nil { - return mcms.Operation{}, - fmt.Errorf("error confirming updateDon call for donID(%d) and plugin type (%d): %w", donID, pluginType, err) + return mcmstypes.Transaction{}, fmt.Errorf("error confirming UpdateDON call in promote candidate (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginType).String(), err) } } + + tx, err := proposalutils.TransactionForChain(homeChain.Selector, capReg.Address().Hex(), updateDonTx.Data(), + big.NewInt(0), string(CapabilitiesRegistry), []string{}) if err != nil { - return mcms.Operation{}, fmt.Errorf("error creating updateDon op for donID(%d) and plugin type (%s): %w", + return mcmstypes.Transaction{}, fmt.Errorf("failed to create UpdateDON mcms tx in promote candidate (don: %d; ptype: %s): %w", donID, types.PluginType(pluginType).String(), err) } - return mcms.Operation{ - To: capReg.Address(), - Data: updateDonTx.Data(), - Value: big.NewInt(0), - }, nil + + return tx, nil } // promoteCandidateForChainOps promotes the candidate commit and exec configs to active by calling promoteCandidateAndRevokeActive on CCIPHome through the UpdateDON call on CapReg contract @@ -1003,16 +1013,16 @@ func promoteCandidateForChainOps( pluginType cctypes.PluginType, allowEmpty bool, mcmsEnabled bool, -) (mcms.Operation, error) { +) (mcmstypes.Transaction, error) { if donID == 0 { - return mcms.Operation{}, errors.New("donID is zero") + return mcmstypes.Transaction{}, errors.New("donID is zero") } digest, err := ccipHome.GetCandidateDigest(nil, donID, uint8(pluginType)) if err != nil { - return mcms.Operation{}, err + return mcmstypes.Transaction{}, err } if digest == [32]byte{} && !allowEmpty { - return mcms.Operation{}, errors.New("candidate config digest is zero, promoting empty config is not allowed") + return mcmstypes.Transaction{}, errors.New("candidate config digest is zero, promoting empty config is not allowed") } fmt.Println("Promoting candidate for plugin", pluginType.String(), "with digest", digest) updatePluginOp, err := promoteCandidateOp( @@ -1026,7 +1036,7 @@ func promoteCandidateForChainOps( mcmsEnabled, ) if err != nil { - return mcms.Operation{}, fmt.Errorf("promote candidate op for plugin %s: %w", pluginType.String(), err) + return mcmstypes.Transaction{}, fmt.Errorf("promote candidate op for plugin %s: %w", pluginType.String(), err) } return updatePluginOp, nil } @@ -1132,17 +1142,17 @@ func RevokeCandidateChangeset(e deployment.Environment, cfg RevokeCandidateChang return deployment.ChangesetOutput{}, nil } - prop, err := proposalutils.BuildProposalFromBatches( - map[uint64]common.Address{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address(), - }, - map[uint64]*gethwrappers.ManyChainMultiSig{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm, - }, - []timelock.BatchChainOperation{{ - ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: ops, - }}, + timelocks := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address().Hex()} + proposers := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm.Address().Hex()} + inspectors := map[uint64]mcmssdk.Inspector{cfg.HomeChainSelector: mcmsevmsdk.NewInspector(e.Chains[cfg.HomeChainSelector].Client)} + batches := []mcmstypes.BatchOperation{{ChainSelector: mcmstypes.ChainSelector(cfg.HomeChainSelector), Transactions: ops}} + + prop, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposers, + inspectors, + batches, fmt.Sprintf("revokeCandidate for don %d", cfg.RemoteChainSelector), cfg.MCMS.MinDelay, ) @@ -1150,11 +1160,7 @@ func RevokeCandidateChangeset(e deployment.Environment, cfg RevokeCandidateChang return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{ - *prop, - }, - }, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*prop}}, nil } func revokeCandidateOps( @@ -1166,7 +1172,7 @@ func revokeCandidateOps( donID uint32, pluginType uint8, mcmsEnabled bool, -) ([]mcms.Operation, error) { +) ([]mcmstypes.Transaction, error) { if donID == 0 { return nil, errors.New("donID is zero") } @@ -1200,22 +1206,28 @@ func revokeCandidateOps( nodes.DefaultF(), ) if err != nil { - return nil, fmt.Errorf("update don w/ revokeCandidate call: %w", deployment.MaybeDataErr(err)) + return nil, fmt.Errorf("failed to call UpdateDON in revoke candidate (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginType).String(), err) } + if !mcmsEnabled { _, err = deployment.ConfirmIfNoErrorWithABI( homeChain, updateDonTx, capabilities_registry.CapabilitiesRegistryABI, err) if err != nil { - return nil, fmt.Errorf("error confirming updateDon call: %w", err) + return nil, fmt.Errorf("error confirming UpdateDON call in revoke candidate (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginType).String(), err) } } - return []mcms.Operation{{ - To: capReg.Address(), - Data: updateDonTx.Data(), - Value: big.NewInt(0), - }}, nil + tx, err := proposalutils.TransactionForChain(homeChain.Selector, capReg.Address().Hex(), updateDonTx.Data(), + big.NewInt(0), string(CapabilitiesRegistry), []string{}) + if err != nil { + return nil, fmt.Errorf("failed to create UpdateDON mcms tx in revoke candidate (don: %d; ptype: %s): %w", + donID, types.PluginType(pluginType).String(), err) + } + + return []mcmstypes.Transaction{tx}, nil } type ChainConfig struct { @@ -1332,33 +1344,30 @@ func UpdateChainConfigChangeset(e deployment.Environment, cfg UpdateChainConfigC return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( - map[uint64]common.Address{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address(), - }, - map[uint64]*gethwrappers.ManyChainMultiSig{ - cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm, - }, - []timelock.BatchChainOperation{{ - ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: []mcms.Operation{ - { - To: state.Chains[cfg.HomeChainSelector].CCIPHome.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }}, + timelocks := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address().Hex()} + proposers := map[uint64]string{cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm.Address().Hex()} + inspectors := map[uint64]mcmssdk.Inspector{cfg.HomeChainSelector: mcmsevmsdk.NewInspector(e.Chains[cfg.HomeChainSelector].Client)} + batchOp, err := proposalutils.BatchOperationForChain(cfg.HomeChainSelector, state.Chains[cfg.HomeChainSelector].CCIPHome.Address().Hex(), + tx.Data(), big.NewInt(0), string(CCIPHome), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create batch operation: %w", err) + } + + prop, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposers, + inspectors, + []mcmstypes.BatchOperation{batchOp}, "Update chain config", cfg.MCMS.MinDelay, ) if err != nil { return deployment.ChangesetOutput{}, err } + e.Logger.Infof("Proposed chain config update on chain %d removes %v, adds %v", cfg.HomeChainSelector, cfg.RemoteChainRemoves, cfg.RemoteChainAdds) - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*prop}}, nil } func isChainConfigEqual(a, b ccip_home.CCIPHomeChainConfig) bool { diff --git a/deployment/ccip/changeset/cs_chain_contracts.go b/deployment/ccip/changeset/cs_chain_contracts.go index 2faffbfc102..4a0c15d4ff5 100644 --- a/deployment/ccip/changeset/cs_chain_contracts.go +++ b/deployment/ccip/changeset/cs_chain_contracts.go @@ -11,10 +11,10 @@ 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" chain_selectors "github.com/smartcontractkit/chain-selectors" + mcmslib "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -143,9 +143,12 @@ func UpdateNonceManagersChangeset(e deployment.Environment, cfg UpdateNonceManag if err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, updates := range cfg.UpdatesByChain { txOpts := e.Chains[chainSel].DeployerKey if cfg.MCMS != nil { @@ -200,39 +203,51 @@ func UpdateNonceManagersChangeset(e deployment.Environment, cfg UpdateNonceManag } } if cfg.MCMS != nil { - ops := make([]mcms.Operation, 0) + mcmsTransactions := make([]mcmstypes.Transaction, 0) if authTx != nil { - ops = append(ops, mcms.Operation{ - To: nm.Address(), - Data: authTx.Data(), - Value: big.NewInt(0), - }) + mcmsTx, err := proposalutils.TransactionForChain(chainSel, nm.Address().Hex(), authTx.Data(), big.NewInt(0), + string(NonceManager), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create transaction for chain %d: %w", chainSel, err) + } + + mcmsTransactions = append(mcmsTransactions, mcmsTx) } if prevRampsTx != nil { - ops = append(ops, mcms.Operation{ - To: nm.Address(), - Data: prevRampsTx.Data(), - Value: big.NewInt(0), - }) + mcmsTx, err := proposalutils.TransactionForChain(chainSel, nm.Address().Hex(), prevRampsTx.Data(), big.NewInt(0), + string(NonceManager), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create transaction for chain %d: %w", chainSel, err) + } + + mcmsTransactions = append(mcmsTransactions, mcmsTx) } - if len(ops) == 0 { + if len(mcmsTransactions) == 0 { return deployment.ChangesetOutput{}, errors.New("no operations to batch") } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: ops, + + batches = append(batches, mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(chainSel), + Transactions: mcmsTransactions, }) - timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() - proposers[chainSel] = s.Chains[chainSel].ProposerMcm + + timelocks[chainSel] = s.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = s.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "Update nonce manager for previous ramps and authorized callers", cfg.MCMS.MinDelay, @@ -240,9 +255,8 @@ func UpdateNonceManagersChangeset(e deployment.Environment, cfg UpdateNonceManag if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type OnRampDestinationUpdate struct { @@ -314,9 +328,12 @@ func UpdateOnRampsDestsChangeset(e deployment.Environment, cfg UpdateOnRampDests if err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, updates := range cfg.UpdatesByChain { txOpts := e.Chains[chainSel].DeployerKey txOpts.Context = e.GetContext() @@ -350,26 +367,31 @@ func UpdateOnRampsDestsChangeset(e deployment.Environment, cfg UpdateOnRampDests if err != nil { return deployment.ChangesetOutput{}, err } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: []mcms.Operation{ - { - To: onRamp.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() - proposers[chainSel] = s.Chains[chainSel].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(chainSel, onRamp.Address().Hex(), tx.Data(), + big.NewInt(0), string(OnRamp), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[chainSel] = s.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = s.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "Update onramp destinations", cfg.MCMS.MinDelay, @@ -377,9 +399,8 @@ func UpdateOnRampsDestsChangeset(e deployment.Environment, cfg UpdateOnRampDests if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type OnRampDynamicConfigUpdate struct { @@ -422,9 +443,12 @@ func UpdateOnRampDynamicConfigChangeset(e deployment.Environment, cfg UpdateOnRa if err := cfg.Validate(e, state); err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, update := range cfg.UpdatesByChain { txOps := e.Chains[chainSel].DeployerKey if cfg.MCMS != nil { @@ -458,33 +482,35 @@ func UpdateOnRampDynamicConfigChangeset(e deployment.Environment, cfg UpdateOnRa if err != nil { return deployment.ChangesetOutput{}, err } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: []mcms.Operation{ - { - To: onRamp.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() - proposers[chainSel] = state.Chains[chainSel].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(chainSel, onRamp.Address().Hex(), tx.Data(), + big.NewInt(0), string(OnRamp), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - proposal, err := proposalutils.BuildProposalFromBatches( - timelocks, proposers, batches, + + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, inspectors, batches, "update onramp dynamic config", cfg.MCMS.MinDelay) if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*proposal}, - }, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type OnRampAllowListUpdate struct { @@ -559,9 +585,12 @@ func UpdateOnRampAllowListChangeset(e deployment.Environment, cfg UpdateOnRampAl if err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for srcSel, updates := range cfg.UpdatesByChain { txOps := e.Chains[srcSel].DeployerKey if cfg.MCMS != nil { @@ -611,26 +640,31 @@ func UpdateOnRampAllowListChangeset(e deployment.Environment, cfg UpdateOnRampAl if err != nil { return deployment.ChangesetOutput{}, err } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(srcSel), - Batch: []mcms.Operation{ - { - To: onRamp.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[srcSel] = onchain.Chains[srcSel].Timelock.Address() - proposers[srcSel] = onchain.Chains[srcSel].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(srcSel, onRamp.Address().Hex(), tx.Data(), + big.NewInt(0), string(OnRamp), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[srcSel] = onchain.Chains[srcSel].Timelock.Address().Hex() + proposers[srcSel] = onchain.Chains[srcSel].ProposerMcm.Address().Hex() + inspectors[srcSel], err = proposalutils.McmsInspectorForChain(e, srcSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", srcSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - proposal, err := proposalutils.BuildProposalFromBatches( + + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "update onramp allowlist", cfg.MCMS.MinDelay, @@ -638,9 +672,8 @@ func UpdateOnRampAllowListChangeset(e deployment.Environment, cfg UpdateOnRampAl if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*proposal}, - }, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type WithdrawOnRampFeeTokensConfig struct { @@ -691,9 +724,12 @@ func WithdrawOnRampFeeTokensChangeset(e deployment.Environment, cfg WithdrawOnRa if err := cfg.Validate(e, state); err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, feeTokens := range cfg.FeeTokensByChain { txOps := e.Chains[chainSel].DeployerKey onRamp := state.Chains[chainSel].OnRamp @@ -706,26 +742,31 @@ func WithdrawOnRampFeeTokensChangeset(e deployment.Environment, cfg WithdrawOnRa if err != nil { return deployment.ChangesetOutput{}, err } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: []mcms.Operation{ - { - To: onRamp.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() - proposers[chainSel] = state.Chains[chainSel].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(chainSel, onRamp.Address().Hex(), tx.Data(), + big.NewInt(0), string(OnRamp), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - proposal, err := proposalutils.BuildProposalFromBatches( + + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "withdraw onramp fee tokens", cfg.MCMS.MinDelay, @@ -733,9 +774,8 @@ func WithdrawOnRampFeeTokensChangeset(e deployment.Environment, cfg WithdrawOnRa if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*proposal}, - }, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type UpdateFeeQuoterPricesConfig struct { @@ -831,9 +871,12 @@ func UpdateFeeQuoterPricesChangeset(e deployment.Environment, cfg UpdateFeeQuote if err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, initialPrice := range cfg.PricesByChain { txOpts := e.Chains[chainSel].DeployerKey if cfg.MCMS != nil { @@ -866,27 +909,31 @@ func UpdateFeeQuoterPricesChangeset(e deployment.Environment, cfg UpdateFeeQuote if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("error updating prices for chain %s: %w", e.Chains[chainSel].String(), err) } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: []mcms.Operation{ - { - To: fq.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() - proposers[chainSel] = s.Chains[chainSel].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(chainSel, fq.Address().Hex(), tx.Data(), + big.NewInt(0), string(FeeQuoter), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[chainSel] = s.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = s.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "Update fq prices", cfg.MCMS.MinDelay, @@ -894,9 +941,8 @@ func UpdateFeeQuoterPricesChangeset(e deployment.Environment, cfg UpdateFeeQuote if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type UpdateFeeQuoterDestsConfig struct { @@ -956,9 +1002,12 @@ func UpdateFeeQuoterDestsChangeset(e deployment.Environment, cfg UpdateFeeQuoter if err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, updates := range cfg.UpdatesByChain { txOpts := e.Chains[chainSel].DeployerKey txOpts.Context = e.GetContext() @@ -982,27 +1031,30 @@ func UpdateFeeQuoterDestsChangeset(e deployment.Environment, cfg UpdateFeeQuoter return deployment.ChangesetOutput{}, err } } else { - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: []mcms.Operation{ - { - To: fq.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() - proposers[chainSel] = s.Chains[chainSel].ProposerMcm + batchOperation, err := proposalutils.BatchOperationForChain(chainSel, fq.Address().Hex(), tx.Data(), + big.NewInt(0), string(FeeQuoter), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[chainSel] = s.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = s.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "Update fq destinations", cfg.MCMS.MinDelay, @@ -1010,9 +1062,8 @@ func UpdateFeeQuoterDestsChangeset(e deployment.Environment, cfg UpdateFeeQuoter if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type OffRampSourceUpdate struct { @@ -1076,9 +1127,12 @@ func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSo if err := cfg.Validate(e, state); err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, updates := range cfg.UpdatesByChain { txOpts := e.Chains[chainSel].DeployerKey txOpts.Context = e.GetContext() @@ -1123,27 +1177,31 @@ func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSo if err != nil { return deployment.ChangesetOutput{}, err } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: []mcms.Operation{ - { - To: offRamp.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() - proposers[chainSel] = state.Chains[chainSel].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(chainSel, offRamp.Address().Hex(), tx.Data(), + big.NewInt(0), string(OffRamp), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "Update offramp sources", cfg.MCMS.MinDelay, @@ -1151,9 +1209,8 @@ func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSo if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type RouterUpdates struct { @@ -1241,9 +1298,12 @@ func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsC if err := cfg.Validate(e, state); err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, update := range cfg.UpdatesByChain { txOpts := e.Chains[chainSel].DeployerKey txOpts.Context = e.GetContext() @@ -1297,27 +1357,31 @@ func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsC if err != nil { return deployment.ChangesetOutput{}, err } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: []mcms.Operation{ - { - To: routerC.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() - proposers[chainSel] = state.Chains[chainSel].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(chainSel, routerC.Address().Hex(), tx.Data(), + big.NewInt(0), string(Router), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "Update router offramps", cfg.MCMS.MinDelay, @@ -1325,9 +1389,8 @@ func UpdateRouterRampsChangeset(e deployment.Environment, cfg UpdateRouterRampsC if err != nil { return deployment.ChangesetOutput{}, err } - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type SetOCR3OffRampConfig struct { @@ -1410,9 +1473,12 @@ func SetOCR3OffRampChangeset(e deployment.Environment, cfg SetOCR3OffRampConfig) if err := cfg.Validate(e, state); err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for _, remote := range cfg.RemoteChainSels { donID, err := internal.DonIDForChain( state.Chains[cfg.HomeChainSel].CapabilityRegistry, @@ -1448,26 +1514,31 @@ func SetOCR3OffRampChangeset(e deployment.Environment, cfg SetOCR3OffRampConfig) if err != nil { return deployment.ChangesetOutput{}, err } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(remote), - Batch: []mcms.Operation{ - { - To: offRamp.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[remote] = state.Chains[remote].Timelock.Address() - proposers[remote] = state.Chains[remote].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(remote, offRamp.Address().Hex(), tx.Data(), + big.NewInt(0), string(OffRamp), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[remote] = state.Chains[remote].Timelock.Address().Hex() + proposers[remote] = state.Chains[remote].ProposerMcm.Address().Hex() + inspectors[remote], err = proposalutils.McmsInspectorForChain(e, remote) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", remote, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "Update OCR3 config", cfg.MCMS.MinDelay, @@ -1475,10 +1546,9 @@ func SetOCR3OffRampChangeset(e deployment.Environment, cfg SetOCR3OffRampConfig) if err != nil { return deployment.ChangesetOutput{}, err } + e.Logger.Info("Proposing OCR3 config update for", cfg.RemoteChainSels) - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } type UpdateDynamicConfigOffRampConfig struct { @@ -1536,9 +1606,12 @@ func UpdateDynamicConfigOffRampChangeset(e deployment.Environment, cfg UpdateDyn if err != nil { return deployment.ChangesetOutput{}, err } - var batches []timelock.BatchChainOperation - timelocks := make(map[uint64]common.Address) - proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + proposers := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for chainSel, params := range cfg.Updates { chain := e.Chains[chainSel] txOpts := e.Chains[chainSel].DeployerKey @@ -1561,38 +1634,41 @@ func UpdateDynamicConfigOffRampChangeset(e deployment.Environment, cfg UpdateDyn if err != nil { return deployment.ChangesetOutput{}, err } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chainSel), - Batch: []mcms.Operation{ - { - To: offRamp.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) - timelocks[chainSel] = state.Chains[chainSel].Timelock.Address() - proposers[chainSel] = state.Chains[chainSel].ProposerMcm + + batchOperation, err := proposalutils.BatchOperationForChain(chainSel, offRamp.Address().Hex(), tx.Data(), + big.NewInt(0), string(OffRamp), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, err + } + batches = append(batches, batchOperation) + + timelocks[chainSel] = state.Chains[chainSel].Timelock.Address().Hex() + proposers[chainSel] = state.Chains[chainSel].ProposerMcm.Address().Hex() + inspectors[chainSel], err = proposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", chainSel, err) + } } } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, proposers, + inspectors, batches, "Update offramp dynamic config", cfg.MCMS.MinDelay, ) - if err != nil { return deployment.ChangesetOutput{}, err } + e.Logger.Infow("Proposing offramp dynamic config update", "config", cfg.Updates) - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } func isOCR3ConfigSetOnOffRamp( diff --git a/deployment/ccip/changeset/cs_home_chain.go b/deployment/ccip/changeset/cs_home_chain.go index b3fbb990991..458356ae25c 100644 --- a/deployment/ccip/changeset/cs_home_chain.go +++ b/deployment/ccip/changeset/cs_home_chain.go @@ -10,9 +10,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "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" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + mcmsevmsdk "github.com/smartcontractkit/mcms/sdk/evm" + mcmstypes "github.com/smartcontractkit/mcms/types" "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -468,8 +469,7 @@ func (c RemoveDONsConfig) Validate(homeChain CCIPChainState) error { } // RemoveDONs removes DONs from the CapabilitiesRegistry contract. -// TODO: Could likely be moved to common, but needs -// a common state struct first. +// TODO: Could likely be moved to common, but needs a common state struct first. func RemoveDONs(e deployment.Environment, cfg RemoveDONsConfig) (deployment.ChangesetOutput, error) { state, err := LoadOnchainState(e) if err != nil { @@ -500,33 +500,31 @@ func RemoveDONs(e deployment.Environment, cfg RemoveDONsConfig) (deployment.Chan e.Logger.Infof("Removed dons using deployer key tx %s", tx.Hash().String()) return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( - map[uint64]common.Address{ - cfg.HomeChainSel: homeChainState.Timelock.Address(), - }, - map[uint64]*gethwrappers.ManyChainMultiSig{ - cfg.HomeChainSel: homeChainState.ProposerMcm, - }, - []timelock.BatchChainOperation{ - { - ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSel), - Batch: []mcms.Operation{ - { - To: homeChainState.CapabilityRegistry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }, - }, + + batchOperation, err := proposalutils.BatchOperationForChain(cfg.HomeChainSel, + homeChainState.CapabilityRegistry.Address().Hex(), tx.Data(), big.NewInt(0), + string(CapabilitiesRegistry), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create batch operation for home chain: %w", err) + } + + timelocks := map[uint64]string{cfg.HomeChainSel: homeChainState.Timelock.Address().Hex()} + proposerMcms := map[uint64]string{cfg.HomeChainSel: homeChainState.ProposerMcm.Address().Hex()} + inspectors := map[uint64]mcmssdk.Inspector{cfg.HomeChainSel: mcmsevmsdk.NewInspector(homeChain.Client)} + + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposerMcms, + inspectors, + []mcmstypes.BatchOperation{batchOperation}, "Remove DONs", cfg.MCMS.MinDelay, ) if err != nil { return deployment.ChangesetOutput{}, err } + e.Logger.Infof("Created proposal to remove dons") - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, - }}, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } diff --git a/deployment/ccip/changeset/cs_update_rmn_config.go b/deployment/ccip/changeset/cs_update_rmn_config.go index a543b622354..b935190fc62 100644 --- a/deployment/ccip/changeset/cs_update_rmn_config.go +++ b/deployment/ccip/changeset/cs_update_rmn_config.go @@ -9,8 +9,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + mcmslib "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -62,42 +63,46 @@ func SetRMNRemoteOnRMNProxyChangeset(e deployment.Environment, cfg SetRMNRemoteO if err := cfg.Validate(state); err != nil { return deployment.ChangesetOutput{}, err } - timelocks, err := state.GetAllTimeLocksForChains(cfg.ChainSelectors) - if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("failed to get timelocks for chains %v: %w", cfg.ChainSelectors, err) - } - multiSigs, err := state.GetAllProposerMCMSForChains(cfg.ChainSelectors) - if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("failed to get proposer MCMS for chains %v: %w", cfg.ChainSelectors, err) - } - var timelockBatch []timelock.BatchChainOperation + + timelocks := BuildTimelockAddressPerChain(e, state) + proposerMcms := BuildProposerMcmAddressesPerChain(e, state) + + inspectors := map[uint64]mcmssdk.Inspector{} + timelockBatch := []mcmstypes.BatchOperation{} for _, sel := range cfg.ChainSelectors { chain, exists := e.Chains[sel] if !exists { return deployment.ChangesetOutput{}, fmt.Errorf("chain %d not found", sel) } + + inspectors[sel], err = proposalutils.McmsInspectorForChain(e, sel) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get mcms inspector for chain %s: %w", chain.String(), err) + } + txOpts := chain.DeployerKey if cfg.MCMSConfig != nil { txOpts = deployment.SimTransactOpts() } - mcmsOps, err := setRMNRemoteOnRMNProxyOp(txOpts, chain, state.Chains[sel], cfg.MCMSConfig != nil) + batchOperation, err := setRMNRemoteOnRMNProxyOp(txOpts, chain, state.Chains[sel], cfg.MCMSConfig != nil) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to set RMNRemote on RMNProxy for chain %s: %w", chain.String(), err) } + if cfg.MCMSConfig != nil { - timelockBatch = append(timelockBatch, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(sel), - Batch: []mcms.Operation{mcmsOps}, - }) + timelockBatch = append(timelockBatch, batchOperation) } } // If we're not using MCMS, we can just return now as we've already confirmed the transactions if len(timelockBatch) == 0 { return deployment.ChangesetOutput{}, nil } - prop, err := proposalutils.BuildProposalFromBatches( + + prop, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), timelocks, - multiSigs, + proposerMcms, + inspectors, timelockBatch, fmt.Sprintf("proposal to set RMNRemote on RMNProxy for chains %v", cfg.ChainSelectors), cfg.MCMSConfig.MinDelay, @@ -106,30 +111,35 @@ func SetRMNRemoteOnRMNProxyChangeset(e deployment.Environment, cfg SetRMNRemoteO return deployment.ChangesetOutput{}, err } return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{ + MCMSTimelockProposals: []mcmslib.TimelockProposal{ *prop, }, }, nil } -func setRMNRemoteOnRMNProxyOp(txOpts *bind.TransactOpts, chain deployment.Chain, chainState CCIPChainState, mcmsEnabled bool) (mcms.Operation, error) { +func setRMNRemoteOnRMNProxyOp( + txOpts *bind.TransactOpts, chain deployment.Chain, chainState CCIPChainState, mcmsEnabled bool, +) (mcmstypes.BatchOperation, error) { rmnProxy := chainState.RMNProxy rmnRemoteAddr := chainState.RMNRemote.Address() setRMNTx, err := rmnProxy.SetARM(txOpts, rmnRemoteAddr) if err != nil { - return mcms.Operation{}, fmt.Errorf("failed to build call data/transaction to set RMNRemote on RMNProxy for chain %s: %w", chain.String(), err) + return mcmstypes.BatchOperation{}, fmt.Errorf("failed to build call data/transaction to set RMNRemote on RMNProxy for chain %s: %w", chain.String(), err) } if !mcmsEnabled { _, err = deployment.ConfirmIfNoErrorWithABI(chain, setRMNTx, rmn_proxy_contract.RMNProxyABI, err) if err != nil { - return mcms.Operation{}, fmt.Errorf("failed to confirm tx to set RMNRemote on RMNProxy for chain %s: %w", chain.String(), deployment.MaybeDataErr(err)) + return mcmstypes.BatchOperation{}, fmt.Errorf("failed to confirm tx to set RMNRemote on RMNProxy for chain %s: %w", chain.String(), deployment.MaybeDataErr(err)) } } - return mcms.Operation{ - To: rmnProxy.Address(), - Data: setRMNTx.Data(), - Value: big.NewInt(0), - }, nil + + batchOperation, err := proposalutils.BatchOperationForChain(chain.Selector, rmnProxy.Address().Hex(), + setRMNTx.Data(), big.NewInt(0), string(RMN), []string{}) + if err != nil { + return mcmstypes.BatchOperation{}, fmt.Errorf("failed to create batch operation for chain%s: %w", chain.String(), err) + } + + return batchOperation, nil } type RMNNopConfig struct { @@ -347,7 +357,6 @@ func SetRMNHomeCandidateConfigChangeset(e deployment.Environment, config SetRMNH if config.MCMSConfig == nil { chain := e.Chains[config.HomeChainSelector] _, err := chain.Confirm(setCandidateTx) - if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm tx for chain %s: %w", homeChain.String(), deployment.MaybeDataErr(err)) } @@ -355,38 +364,33 @@ func SetRMNHomeCandidateConfigChangeset(e deployment.Environment, config SetRMNH return deployment.ChangesetOutput{}, nil } - op := mcms.Operation{ - To: rmnHome.Address(), - Data: setCandidateTx.Data(), - Value: big.NewInt(0), + operation, err := proposalutils.BatchOperationForChain(homeChain.Selector, rmnHome.Address().Hex(), + setCandidateTx.Data(), big.NewInt(0), string(RMN), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create batch operation for chain %s: %w", homeChain.String(), err) } - batches := []timelock.BatchChainOperation{ - { - ChainIdentifier: mcms.ChainIdentifier(config.HomeChainSelector), - Batch: []mcms.Operation{op}, - }, + timelocks := BuildTimelockAddressPerChain(e, state) + proposerMcms := BuildProposerMcmAddressesPerChain(e, state) + inspectors, err := proposalutils.McmsInspectors(e) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get mcms inspector for chain %s: %w", homeChain.String(), err) } - timelocksPerChain := BuildTimelockAddressPerChain(e, state) - - proposerMCMSes := BuildProposerPerChain(e, state) - - prop, err := proposalutils.BuildProposalFromBatches( - timelocksPerChain, - proposerMCMSes, - batches, + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposerMcms, + inspectors, + []mcmstypes.BatchOperation{operation}, "proposal to set candidate config", config.MCMSConfig.MinDelay, ) - if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal for chain %s: %w", homeChain.String(), err) } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*prop}, - }, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } func PromoteRMNHomeCandidateConfigChangeset(e deployment.Environment, config PromoteRMNHomeCandidateConfig) (deployment.ChangesetOutput, error) { @@ -430,7 +434,6 @@ func PromoteRMNHomeCandidateConfigChangeset(e deployment.Environment, config Pro if config.MCMSConfig == nil { chain := e.Chains[config.HomeChainSelector] _, err := chain.Confirm(promoteCandidateTx) - if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm tx for chain %s: %w", homeChain.String(), deployment.MaybeDataErr(err)) } @@ -438,37 +441,36 @@ func PromoteRMNHomeCandidateConfigChangeset(e deployment.Environment, config Pro return deployment.ChangesetOutput{}, nil } - op := mcms.Operation{ - To: rmnHome.Address(), - Data: promoteCandidateTx.Data(), - Value: big.NewInt(0), - } - - batches := []timelock.BatchChainOperation{ - { - ChainIdentifier: mcms.ChainIdentifier(config.HomeChainSelector), - Batch: []mcms.Operation{op}, - }, + operation, err := proposalutils.BatchOperationForChain(homeChain.Selector, rmnHome.Address().Hex(), + promoteCandidateTx.Data(), big.NewInt(0), string(RMN), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create batch operation for chain %s: %w", homeChain.String(), err) } - timelocksPerChain := BuildTimelockAddressPerChain(e, state) + timelocks := BuildTimelockAddressPerChain(e, state) + proposerMcms := BuildProposerMcmAddressesPerChain(e, state) - proposerMCMSes := BuildProposerPerChain(e, state) + inspectors := map[uint64]mcmssdk.Inspector{} + inspectors[config.HomeChainSelector], err = proposalutils.McmsInspectorForChain(e, config.HomeChainSelector) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get mcms inspector for chain %s: %w", homeChain.String(), err) + } - prop, err := proposalutils.BuildProposalFromBatches( - timelocksPerChain, - proposerMCMSes, - batches, + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposerMcms, + inspectors, + []mcmstypes.BatchOperation{operation}, "proposal to promote candidate config", config.MCMSConfig.MinDelay, ) - if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal for chain %s: %w", homeChain.String(), err) } return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*prop}, + MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}, }, nil } @@ -693,7 +695,7 @@ func SetRMNRemoteConfigChangeset(e deployment.Environment, config SetRMNRemoteCo } rmnRemotePerChain := BuildRMNRemotePerChain(e, state) - batches := make([]timelock.BatchChainOperation, 0) + batches := make([]mcmstypes.BatchOperation, 0) for chain, remoteConfig := range config.RMNRemoteConfigs { remote, ok := rmnRemotePerChain[chain] if !ok { @@ -731,31 +733,31 @@ func SetRMNRemoteConfigChangeset(e deployment.Environment, config SetRMNRemoteCo } } - op := mcms.Operation{ - To: remote.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - } - - batch := timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(chain), - Batch: []mcms.Operation{op}, + operation, err := proposalutils.BatchOperationForChain(e.Chains[chain].Selector, remote.Address().Hex(), + tx.Data(), big.NewInt(0), string(RMN), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create batch operation for chain %s: %w", homeChain.String(), err) } - batches = append(batches, batch) + batches = append(batches, operation) } if config.MCMSConfig == nil { return deployment.ChangesetOutput{}, nil } - timelocksPerChain := BuildTimelockAddressPerChain(e, state) - - proposerMCMSes := BuildProposerPerChain(e, state) + timelocks := BuildTimelockAddressPerChain(e, state) + proposerMcms := BuildProposerMcmAddressesPerChain(e, state) + inspectors, err := proposalutils.McmsInspectors(e) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get mcms inspector for chain %s: %w", homeChain.String(), err) + } - prop, err := proposalutils.BuildProposalFromBatches( - timelocksPerChain, - proposerMCMSes, + proposal, err := proposalutils.BuildProposalFromBatchesV2( + e.GetContext(), + timelocks, + proposerMcms, + inspectors, batches, "proposal to promote candidate config", config.MCMSConfig.MinDelay, @@ -765,7 +767,5 @@ func SetRMNRemoteConfigChangeset(e deployment.Environment, config SetRMNRemoteCo return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal for chain %s: %w", homeChain.String(), err) } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*prop}, - }, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}}, nil } diff --git a/deployment/ccip/changeset/deployer_group.go b/deployment/ccip/changeset/deployer_group.go index 6f3732a760b..84610b4b007 100644 --- a/deployment/ccip/changeset/deployer_group.go +++ b/deployment/ccip/changeset/deployer_group.go @@ -12,9 +12,8 @@ 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" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -201,21 +200,22 @@ func (d *DeployerGroup) Enact() (deployment.ChangesetOutput, error) { func (d *DeployerGroup) enactMcms() (deployment.ChangesetOutput, error) { contexts := d.getContextChainInOrder() - proposals := make([]timelock.MCMSWithTimelockProposal, 0) + proposals := make([]mcmslib.TimelockProposal, 0) for _, dc := range contexts { - batches := make([]timelock.BatchChainOperation, 0) + batches := make([]mcmstypes.BatchOperation, 0) for selector, txs := range dc.transactions { - mcmOps := make([]mcms.Operation, len(txs)) + mcmTransactions := make([]mcmstypes.Transaction, len(txs)) for i, tx := range txs { - mcmOps[i] = mcms.Operation{ - To: *tx.To(), - Data: tx.Data(), - Value: tx.Value(), + var err error + mcmTransactions[i], err = proposalutils.TransactionForChain(selector, tx.To().Hex(), tx.Data(), tx.Value(), "", []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to build mcms transaction: %w", err) } } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(selector), - Batch: mcmOps, + + batches = append(batches, mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(selector), + Transactions: mcmTransactions, }) } @@ -224,50 +224,53 @@ func (d *DeployerGroup) enactMcms() (deployment.ChangesetOutput, error) { continue } - timelocksPerChain := BuildTimelockAddressPerChain(d.e, d.state) - - proposerMCMSes := BuildProposerPerChain(d.e, d.state) + timelocks := BuildTimelockAddressPerChain(d.e, d.state) + proposerMcms := BuildProposerMcmAddressesPerChain(d.e, d.state) + inspectors, err := proposalutils.McmsInspectors(d.e) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get mcms inspector for chain: %w", err) + } - prop, err := proposalutils.BuildProposalFromBatches( - timelocksPerChain, - proposerMCMSes, + proposal, err := proposalutils.BuildProposalFromBatchesV2( + d.e.GetContext(), + timelocks, + proposerMcms, + inspectors, batches, dc.description, d.mcmConfig.MinDelay, ) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal %w", err) + } // Update the proposal metadata to incorporate the startingOpCount // from the previous proposal if len(proposals) > 0 { previousProposal := proposals[len(proposals)-1] for chain, metadata := range previousProposal.ChainMetadata { - nextStartingOp := metadata.StartingOpCount + getBatchCountForChain(chain, prop) - prop.ChainMetadata[chain] = mcms.ChainMetadata{ + nextStartingOp := metadata.StartingOpCount + getBatchCountForChain(chain, proposal) + proposal.ChainMetadata[chain] = mcmstypes.ChainMetadata{ StartingOpCount: nextStartingOp, - MCMAddress: prop.ChainMetadata[chain].MCMAddress, + MCMAddress: proposal.ChainMetadata[chain].MCMAddress, } } } - if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal %w", err) - } - - proposals = append(proposals, *prop) + proposals = append(proposals, *proposal) } - return deployment.ChangesetOutput{ - Proposals: proposals, - }, nil + return deployment.ChangesetOutput{MCMSTimelockProposals: proposals}, nil } -func getBatchCountForChain(chain mcms.ChainIdentifier, m *timelock.MCMSWithTimelockProposal) uint64 { - batches := make([]timelock.BatchChainOperation, 0) - for _, t := range m.Transactions { - if t.ChainIdentifier == chain { - batches = append(batches, t) +func getBatchCountForChain(chain mcmstypes.ChainSelector, timelockProposal *mcmslib.TimelockProposal) uint64 { + batches := make([]mcmstypes.BatchOperation, 0) + for _, batchOperation := range timelockProposal.Operations { + if batchOperation.ChainSelector == chain { + batches = append(batches, batchOperation) } } + return uint64(len(batches)) } @@ -310,19 +313,18 @@ func BuildTimelockPerChain(e deployment.Environment, state CCIPOnChainState) map return timelocksPerChain } -func BuildTimelockAddressPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]common.Address { - timelocksPerChain := BuildTimelockPerChain(e, state) - timelockAddressPerChain := make(map[uint64]common.Address) - for chain, timelock := range timelocksPerChain { - timelockAddressPerChain[chain] = timelock.Timelock.Address() +func BuildTimelockAddressPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]string { + addressPerChain := make(map[uint64]string) + for _, chain := range e.Chains { + addressPerChain[chain.Selector] = state.Chains[chain.Selector].Timelock.Address().Hex() } - return timelockAddressPerChain + return addressPerChain } -func BuildProposerPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*gethwrappers.ManyChainMultiSig { - proposerPerChain := make(map[uint64]*gethwrappers.ManyChainMultiSig) +func BuildProposerMcmAddressesPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]string { + addressPerChain := make(map[uint64]string) for _, chain := range e.Chains { - proposerPerChain[chain.Selector] = state.Chains[chain.Selector].ProposerMcm + addressPerChain[chain.Selector] = state.Chains[chain.Selector].ProposerMcm.Address().Hex() } - return proposerPerChain + return addressPerChain } diff --git a/deployment/ccip/changeset/deployer_group_test.go b/deployment/ccip/changeset/deployer_group_test.go index 21f6688c815..cd58633df7c 100644 --- a/deployment/ccip/changeset/deployer_group_test.go +++ b/deployment/ccip/changeset/deployer_group_test.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" @@ -331,13 +331,13 @@ func TestDeployerGroupGenerateMultipleProposals(t *testing.T) { cs, err := dummyDeployerGroupMintMultiDeploymentContextChangeset(e.Env, tc) require.NoError(t, err) - require.Len(t, cs.Proposals, len(tc.mints)) - require.Equal(t, "mint tokens 1", cs.Proposals[0].Description) - require.Equal(t, "mint tokens 2", cs.Proposals[1].Description) - require.Equal(t, "mint tokens 3", cs.Proposals[2].Description) - require.Equal(t, uint64(2), cs.Proposals[0].ChainMetadata[mcms.ChainIdentifier(e.Env.AllChainSelectors()[tc.mints[0].selectorIndex])].StartingOpCount) - require.Equal(t, uint64(3), cs.Proposals[1].ChainMetadata[mcms.ChainIdentifier(e.Env.AllChainSelectors()[tc.mints[1].selectorIndex])].StartingOpCount) - require.Equal(t, uint64(2), cs.Proposals[2].ChainMetadata[mcms.ChainIdentifier(e.Env.AllChainSelectors()[tc.mints[2].selectorIndex])].StartingOpCount) + require.Len(t, cs.MCMSTimelockProposals, len(tc.mints)) + require.Equal(t, "mint tokens 1", cs.MCMSTimelockProposals[0].Description) + require.Equal(t, "mint tokens 2", cs.MCMSTimelockProposals[1].Description) + require.Equal(t, "mint tokens 3", cs.MCMSTimelockProposals[2].Description) + require.Equal(t, uint64(2), cs.MCMSTimelockProposals[0].ChainMetadata[mcmstypes.ChainSelector(e.Env.AllChainSelectors()[tc.mints[0].selectorIndex])].StartingOpCount) + require.Equal(t, uint64(3), cs.MCMSTimelockProposals[1].ChainMetadata[mcmstypes.ChainSelector(e.Env.AllChainSelectors()[tc.mints[1].selectorIndex])].StartingOpCount) + require.Equal(t, uint64(2), cs.MCMSTimelockProposals[2].ChainMetadata[mcmstypes.ChainSelector(e.Env.AllChainSelectors()[tc.mints[2].selectorIndex])].StartingOpCount) } func TestDeployerGroupMultipleProposalsMCMS(t *testing.T) { @@ -424,5 +424,5 @@ func TestEmptyBatch(t *testing.T) { result, err := dummyEmptyBatchChangeset(e.Env, cfg) require.NoError(t, err) - require.Empty(t, result.Proposals) + require.Empty(t, result.MCMSTimelockProposals) } diff --git a/deployment/ccip/changeset/v1_5/cs_rmn.go b/deployment/ccip/changeset/v1_5/cs_rmn.go index 539dc5f4d5c..1245d907d81 100644 --- a/deployment/ccip/changeset/v1_5/cs_rmn.go +++ b/deployment/ccip/changeset/v1_5/cs_rmn.go @@ -7,9 +7,9 @@ import ( "slices" "github.com/ethereum/go-ethereum/common" - "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" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" @@ -104,18 +104,22 @@ func PermaBlessCommitStoreChangeset(env deployment.Environment, c PermaBlessComm if err := c.Validate(env); err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("invalid PermaBlessCommitStoreConfig: %w", err) } + state, err := changeset.LoadOnchainState(env) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) } - ops := make([]timelock.BatchChainOperation, 0) - timelocks := make(map[uint64]common.Address) - proposerMCM := make(map[uint64]*gethwrappers.ManyChainMultiSig) + + ops := make([]mcmstypes.BatchOperation, 0) + timelocks := make(map[uint64]string) + proposerMcms := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + for destChain, cfg := range c.Configs { destState := state.Chains[destChain] RMN := destState.RMN - var removes []common.Address - var adds []common.Address + + var removes, adds []common.Address for _, sourceCfg := range cfg.Sources { commitStore := destState.CommitStore[sourceCfg.SourceChainSelector] if sourceCfg.PermaBless { @@ -124,11 +128,16 @@ func PermaBlessCommitStoreChangeset(env deployment.Environment, c PermaBlessComm removes = append(removes, commitStore.Address()) } } + txOpts := env.Chains[destChain].DeployerKey if c.MCMSConfig != nil { txOpts = deployment.SimTransactOpts() } tx, err := RMN.OwnerRemoveThenAddPermaBlessedCommitStores(txOpts, removes, adds) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if c.MCMSConfig == nil { _, err = deployment.ConfirmIfNoErrorWithABI(env.Chains[destChain], tx, rmn_contract.RMNContractABI, err) if err != nil { @@ -137,25 +146,31 @@ func PermaBlessCommitStoreChangeset(env deployment.Environment, c PermaBlessComm env.Logger.Infof("PermaBlessed commit stores on chain %d removed %v, added %v", destChain, removes, adds) continue } - timelocks[destChain] = destState.Timelock.Address() - proposerMCM[destChain] = destState.ProposerMcm - ops = append(ops, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(destChain), - Batch: []mcms.Operation{ - { - To: RMN.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }) + + timelocks[destChain] = destState.Timelock.Address().Hex() + proposerMcms[destChain] = destState.ProposerMcm.Address().Hex() + inspectors[destChain], err = proposalutils.McmsInspectorForChain(env, destChain) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get inspector for chain %d: %w", destChain, err) + } + + batchOperation, err := proposalutils.BatchOperationForChain(destChain, RMN.Address().Hex(), tx.Data(), big.NewInt(0), + string(changeset.RMN), []string{}) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to create batch operation for chain %d: %w", destChain, err) + } + + ops = append(ops, batchOperation) } if c.MCMSConfig == nil { return deployment.ChangesetOutput{}, nil } - p, err := proposalutils.BuildProposalFromBatches( + + timelockProposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocks, - proposerMCM, + proposerMcms, + inspectors, ops, "PermaBless commit stores on RMN", c.MCMSConfig.MinDelay, @@ -163,8 +178,9 @@ func PermaBlessCommitStoreChangeset(env deployment.Environment, c PermaBlessComm if err != nil { return deployment.ChangesetOutput{}, err } + env.Logger.Infof("perma bless commit stores proposal created with %d operations", len(ops)) - return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ - *p, + return deployment.ChangesetOutput{MCMSTimelockProposals: []mcmslib.TimelockProposal{ + *timelockProposal, }}, nil } diff --git a/deployment/common/proposalutils/mcms_test_helpers.go b/deployment/common/proposalutils/mcms_test_helpers.go index a3e3047fa2e..c5a62193872 100644 --- a/deployment/common/proposalutils/mcms_test_helpers.go +++ b/deployment/common/proposalutils/mcms_test_helpers.go @@ -4,6 +4,7 @@ import ( "crypto/ecdsa" "fmt" "math/big" + "slices" "testing" "time" @@ -278,7 +279,8 @@ func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, tim // build a "chainSelector => executor" map executorsMap := map[mcmstypes.ChainSelector]mcmssdk.TimelockExecutor{} - for _, op := range timelockProposal.Operations { + callProxies := make([]string, len(timelockProposal.Operations)) + for i, op := range timelockProposal.Operations { family, err := chainsel.GetSelectorFamily(uint64(op.ChainSelector)) require.NoError(t, err) @@ -287,10 +289,13 @@ func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, tim executorsMap[op.ChainSelector] = mcmsevmsdk.NewTimelockExecutor( env.Chains[uint64(op.ChainSelector)].Client, env.Chains[uint64(op.ChainSelector)].DeployerKey) + callProxies[i] = findCallProxyAddress(t, env, uint64(op.ChainSelector)) + case chainsel.FamilySolana: executorsMap[op.ChainSelector] = mcmssolanasdk.NewTimelockExecutor( env.SolChains[uint64(op.ChainSelector)].Client, *env.SolChains[uint64(op.ChainSelector)].DeployerKey) + default: require.FailNow(t, "unsupported chain family") } @@ -306,7 +311,12 @@ func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, tim // execute each operation sequentially var tx = mcmstypes.TransactionResult{} for i, op := range timelockProposal.Operations { - tx, err = timelockExecutable.Execute(env.GetContext(), i, opts...) + opOpts := slices.Clone(opts) + if callProxies[i] != "" { + opOpts = append(opOpts, mcmslib.WithCallProxy(callProxies[i])) + } + + tx, err = timelockExecutable.Execute(env.GetContext(), i, opOpts...) if err != nil { return fmt.Errorf("[ExecuteMCMSTimelockProposalV2] Execute failed: %w", err) } @@ -345,3 +355,17 @@ func SingleGroupTimelockConfigV2(t *testing.T) commontypes.MCMSWithTimelockConfi TimelockMinDelay: big.NewInt(0), } } + +func findCallProxyAddress(t *testing.T, env deployment.Environment, chainSelector uint64) string { + addressesForChain, err := env.ExistingAddresses.AddressesForChain(chainSelector) + require.NoError(t, err) + + for address, tvStr := range addressesForChain { + if tvStr.Type == commontypes.CallProxy && tvStr.Version == deployment.Version1_0_0 { + return address + } + } + + require.FailNow(t, "unable to find call proxy address") + return "" +}