Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add changeset for set config on all 3 mcms contracts [DPA-1392] #15684

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 206 additions & 0 deletions deployment/common/changeset/set_config_mcms.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package changeset

import (
"errors"
"fmt"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/config"
"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"

"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/common/proposalutils"
commontypes "github.com/smartcontractkit/chainlink/deployment/common/types"
)

type ConfigPerRole struct {
Proposer config.Config
Canceller config.Config
Bypasser config.Config
}
type ProposalConfig struct {
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
MinDelay time.Duration // delay for timelock worker to execute the transfers.
}

type SetConfigParams struct {
ConfigsPerChain map[uint64]ConfigPerRole
ProposalConfig *ProposalConfig
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
}

var _ deployment.ChangeSet[SetConfigParams] = SetConfigMCMS

// Validate checks that the SetConfigParams is valid
func (cfg SetConfigParams) Validate(e deployment.Environment, selectors []uint64) error {
// configs should have at least one chain
state, err := MaybeLoadMCMSWithTimelockState(e, selectors)
if err != nil {
return err
}
if len(cfg.ConfigsPerChain) == 0 {
return errors.New("no chain configs provided")
}
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
for chainSelector, c := range cfg.ConfigsPerChain {
family, err := chain_selectors.GetSelectorFamily(chainSelector)
if err != nil {
return err
}
if family != chain_selectors.FamilyEVM {
return fmt.Errorf("chain selector: %d is not an ethereum chain", chainSelector)
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
}
_, ok := e.Chains[chainSelector]
if !ok {
return fmt.Errorf("chain selector: %d not found in environment", chainSelector)
}
_, ok = state[chainSelector]
if !ok {
return fmt.Errorf("chain selector: %d not found for MCMS state", chainSelector)
}
if err := c.Proposer.Validate(); err != nil {
return err
}
if err := c.Canceller.Validate(); err != nil {
return err
}
if err := c.Bypasser.Validate(); err != nil {
return err
}
}
return nil
}

// setConfigOrTxData executes set config tx or gets the tx data for the MCMS proposal
func setConfigOrTxData(chain deployment.Chain, cfg config.Config, contract *gethwrappers.ManyChainMultiSig, useMCMS bool) (*types.Transaction, error) {
groupQuorums, groupParents, signerAddresses, signerGroups := cfg.ExtractSetConfigInputs()
opts := deployment.SimTransactOpts()
if !useMCMS {
opts = chain.DeployerKey
}
tx, err := contract.SetConfig(opts, signerAddresses, signerGroups, groupQuorums, groupParents, false)
if err != nil {
return nil, err
}
if !useMCMS {
_, err = deployment.ConfirmIfNoError(chain, tx, err)
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}
}
return tx, nil
}

type setConfigTxs struct {
proposerTx *types.Transaction
cancellerTx *types.Transaction
bypasserTx *types.Transaction
}

// setConfigPerRole sets the configuration for each of the MCMS contract roles on the mcmsState.
func setConfigPerRole(chain deployment.Chain, cfg ConfigPerRole, mcmsState *MCMSWithTimelockState, useMCMS bool) (setConfigTxs, error) {
// Proposer set config
proposerTx, err := setConfigOrTxData(chain, cfg.Proposer, mcmsState.ProposerMcm, useMCMS)
if err != nil {
return setConfigTxs{}, err
}
// Canceller set config
cancellerTx, err := setConfigOrTxData(chain, cfg.Canceller, mcmsState.CancellerMcm, useMCMS)
if err != nil {
return setConfigTxs{}, err
}
// Bypasser set config
bypasserTx, err := setConfigOrTxData(chain, cfg.Bypasser, mcmsState.BypasserMcm, useMCMS)

ecPablo marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return setConfigTxs{}, err
}
return setConfigTxs{
proposerTx: proposerTx,
cancellerTx: cancellerTx,
bypasserTx: bypasserTx,
}, nil
}
func addTxsToProposalBatch(setConfigTxsChain setConfigTxs, chainSelector uint64, state MCMSWithTimelockState) timelock.BatchChainOperation {
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
result := timelock.BatchChainOperation{
ChainIdentifier: mcms.ChainIdentifier(chainSelector),
Batch: []mcms.Operation{},
}
result.Batch = append(result.Batch, mcms.Operation{
To: state.ProposerMcm.Address(),
Data: setConfigTxsChain.proposerTx.Data(),
Value: big.NewInt(0),
ContractType: string(commontypes.ProposerManyChainMultisig),
})
result.Batch = append(result.Batch, mcms.Operation{
To: state.CancellerMcm.Address(),
Data: setConfigTxsChain.cancellerTx.Data(),
Value: big.NewInt(0),
ContractType: string(commontypes.CancellerManyChainMultisig),
})
result.Batch = append(result.Batch, mcms.Operation{
To: state.BypasserMcm.Address(),
Data: setConfigTxsChain.bypasserTx.Data(),
Value: big.NewInt(0),
ContractType: string(commontypes.BypasserManyChainMultisig),
})
return result
}

// SetConfigMCMS sets the configuration of the MCMS contract on the chain identified by the chainSelector.
func SetConfigMCMS(e deployment.Environment, cfg SetConfigParams) (deployment.ChangesetOutput, error) {
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
selectors := []uint64{}
for chainSelector := range cfg.ConfigsPerChain {
selectors = append(selectors, chainSelector)
}
useMCMS := cfg.ProposalConfig != nil
err := cfg.Validate(e, selectors)
if err != nil {
return deployment.ChangesetOutput{}, err
}

batches := []timelock.BatchChainOperation{}
timelocksPerChain := map[uint64]common.Address{}
proposerMcmsPerChain := map[uint64]*gethwrappers.ManyChainMultiSig{}

mcmsStatePerChain, err := MaybeLoadMCMSWithTimelockState(e, selectors)
if err != nil {
return deployment.ChangesetOutput{}, err
}

for chainSelector, c := range cfg.ConfigsPerChain {
chain, ok := e.Chains[chainSelector]
if !ok {
return deployment.ChangesetOutput{}, errors.New("chain not found in environment")
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
}
state, ok := mcmsStatePerChain[chainSelector]
if !ok {
return deployment.ChangesetOutput{}, fmt.Errorf("MCMS state not found for chain selector: %d", chainSelector)
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
}
timelocksPerChain[chainSelector] = state.Timelock.Address()
proposerMcmsPerChain[chainSelector] = state.ProposerMcm
setConfigTxsChain, err := setConfigPerRole(chain, c, state, useMCMS)
if err != nil {
return deployment.ChangesetOutput{}, err
}
if useMCMS {
batch := addTxsToProposalBatch(setConfigTxsChain, chainSelector, *state)
batches = append(batches, batch)
}

}

if useMCMS {
// Create MCMS with timelock proposal
proposal, err := proposalutils.BuildProposalFromBatches(timelocksPerChain, proposerMcmsPerChain, batches, "Set config proposal", cfg.ProposalConfig.MinDelay)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal from batch: %w", err)
}
return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{*proposal}}, nil
}

return deployment.ChangesetOutput{}, nil
ecPablo marked this conversation as resolved.
Show resolved Hide resolved
}
Loading
Loading