-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add changeset for set config on all 3 mcms contracts
- Loading branch information
Showing
2 changed files
with
533 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | ||
MinDelay time.Duration // delay for timelock worker to execute the transfers. | ||
} | ||
|
||
type SetConfigParams struct { | ||
ConfigsPerChain map[uint64]ConfigPerRole | ||
ProposalConfig *ProposalConfig | ||
} | ||
|
||
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") | ||
} | ||
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) | ||
} | ||
_, 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) | ||
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) | ||
|
||
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 { | ||
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) { | ||
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") | ||
} | ||
state, ok := mcmsStatePerChain[chainSelector] | ||
if !ok { | ||
return deployment.ChangesetOutput{}, fmt.Errorf("MCMS state not found for chain selector: %d", chainSelector) | ||
} | ||
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 | ||
} |
Oops, something went wrong.