Skip to content

Commit 0db7a36

Browse files
authored
chore: refactor mcms evm sequences and operations (#82)
Moves EVM related sequences and operations to the legacy/mcms directory. Performs some renaming and refactoring to make the code more readable.
1 parent 7a56e02 commit 0db7a36

23 files changed

Lines changed: 393 additions & 622 deletions

legacy/mcms/changesets/deploy_mcms_with_timelock.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313

1414
cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils"
1515

16+
evmchangesets "github.com/smartcontractkit/cld-changesets/legacy/mcms/internal/family/evm/changesets"
1617
"github.com/smartcontractkit/cld-changesets/legacy/pkg/family/evm"
17-
evmchangesets "github.com/smartcontractkit/cld-changesets/legacy/pkg/family/evm/changesets"
1818
solchangesets "github.com/smartcontractkit/cld-changesets/legacy/pkg/family/solana/changesets"
1919
opsevm "github.com/smartcontractkit/cld-changesets/pkg/family/evm/operations"
2020

@@ -138,7 +138,7 @@ func DeployMCMSWithTimelockV2(
138138
if s != nil {
139139
chainstate = s[chainSel]
140140
}
141-
reports, err := evmchangesets.DeployMCMSWithTimelockContractsEVM(env, env.BlockChains.EVMChains()[chainSel], newAddresses, cfg, chainstate)
141+
reports, err := evmchangesets.DeployMCMSWithTimelockContracts(env, env.BlockChains.EVMChains()[chainSel], newAddresses, cfg, chainstate)
142142
mu.Lock()
143143
allReports = append(allReports, reports...)
144144
mu.Unlock()

legacy/mcms/changesets/firedrill.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func (MCMSSignFireDrillChangeset) Apply(e cldf.Environment, cfg FireDrillConfig)
9191
deps := mcops.FireDrillDeps{Environment: e}
9292
input := mcops.FireDrillInput{TimelockCfg: cfg.TimelockCfg, Selectors: cfg.Selectors}
9393

94-
report, err := fwops.ExecuteOperation[mcops.FireDrillInput, mcops.FireDrillOutput, mcops.FireDrillDeps](
94+
report, err := fwops.ExecuteOperation(
9595
e.OperationsBundle,
9696
mcops.BuildMCMSFiredrillProposalOp,
9797
deps,

legacy/mcms/changesets/transfer_to_mcms_with_timelock.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,21 @@ import (
88

99
"github.com/ethereum/go-ethereum/accounts/abi/bind"
1010
"github.com/ethereum/go-ethereum/common"
11+
1112
owner_helpers "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers"
13+
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
1214
mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms"
15+
cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils"
16+
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
17+
"github.com/smartcontractkit/chainlink-evm/gethwrappers/shared/generated/initial/burn_mint_erc677"
1318
mcmslib "github.com/smartcontractkit/mcms"
1419
"github.com/smartcontractkit/mcms/sdk"
1520
"github.com/smartcontractkit/mcms/sdk/evm"
1621
mcmstypes "github.com/smartcontractkit/mcms/types"
1722

18-
evmstate "github.com/smartcontractkit/cld-changesets/legacy/pkg/family/evm"
19-
seqs "github.com/smartcontractkit/cld-changesets/pkg/family/evm/sequences"
20-
21-
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
22-
cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils"
23-
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
24-
"github.com/smartcontractkit/chainlink-evm/gethwrappers/shared/generated/initial/burn_mint_erc677"
25-
23+
seqevm "github.com/smartcontractkit/cld-changesets/legacy/mcms/internal/family/evm/sequences"
2624
"github.com/smartcontractkit/cld-changesets/legacy/mcms/proposeutils"
25+
evmstate "github.com/smartcontractkit/cld-changesets/legacy/pkg/family/evm"
2726
)
2827

2928
type TransferToMCMSWithTimelockConfig struct {
@@ -135,11 +134,11 @@ func TransferToMCMSWithTimelockV2(
135134
e.Logger.Infof("timelock on chain %d is %s, proposer is %s", chainSelector, timelockAddr, proposerAddr)
136135
inspectorPerChain[chainSelector] = evm.NewInspector(evmChains[chainSelector].Client)
137136

138-
seqReport, err := operations.ExecuteSequence(e.OperationsBundle, seqs.SeqTransferToMCMSWithTimelockV2,
139-
seqs.SeqTransferToMCMSWithTimelockV2Deps{
137+
seqReport, err := operations.ExecuteSequence(e.OperationsBundle, seqevm.SeqTransferToMCMSWithTimelock,
138+
seqevm.SeqTransferToMCMSWithTimelockDeps{
140139
Chain: evmChains[chainSelector],
141140
},
142-
seqs.SeqTransferToMCMSWithTimelockV2Input{
141+
seqevm.SeqTransferToMCMSWithTimelockInput{
143142
ChainSelector: chainSelector,
144143
Timelock: common.HexToAddress(timelockAddr),
145144
Contracts: contracts,

legacy/pkg/family/evm/changesets/deploy_mcms_with_timelock.go renamed to legacy/mcms/internal/family/evm/changesets/deploy_mcms_with_timelock.go

Lines changed: 22 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
11
package changesets
22

33
import (
4-
"context"
5-
"errors"
6-
"fmt"
7-
"math"
8-
"math/big"
9-
"slices"
10-
11-
"github.com/ethereum/go-ethereum/accounts/abi/bind"
124
"github.com/ethereum/go-ethereum/common"
5+
136
bindings "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers"
147
cldf_evm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm"
158
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
169
mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms"
1710
cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils"
1811
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
19-
"github.com/spf13/cast"
2012

21-
"github.com/smartcontractkit/cld-changesets/internal/mcmsrole"
13+
opevm "github.com/smartcontractkit/cld-changesets/legacy/mcms/internal/family/evm/operations"
14+
seqevm "github.com/smartcontractkit/cld-changesets/legacy/mcms/internal/family/evm/sequences"
2215
evmstate "github.com/smartcontractkit/cld-changesets/legacy/pkg/family/evm"
23-
opsevm "github.com/smartcontractkit/cld-changesets/pkg/family/evm/operations"
24-
seqs "github.com/smartcontractkit/cld-changesets/pkg/family/evm/sequences"
16+
oputils "github.com/smartcontractkit/cld-changesets/pkg/family/evm/operations"
2517
)
2618

2719
// DeployMCMSOption is a function that modifies a TypeAndVersion before or after deployment.
@@ -43,12 +35,14 @@ type MCMSWithTimelockEVMDeploy struct {
4335
CallProxy *cldf.ContractDeploy[*bindings.CallProxy]
4436
}
4537

46-
// DeployMCMSWithTimelockContractsEVM deploys an MCMS for
38+
// DeployMCMSWithTimelockContracts deploys an MCMS for
4739
// each of the timelock roles Bypasser, ProposerMcm, Canceller on an EVM chain.
4840
// MCMS contracts for the given configuration
4941
// as well as the timelock. It's not necessarily the only way to use
5042
// the timelock and MCMS, but its reasonable pattern.
51-
func DeployMCMSWithTimelockContractsEVM(
43+
//
44+
// This is a deployment helper invoked by DeployMCMSWithTimelock, not a standalone Changeset.
45+
func DeployMCMSWithTimelockContracts(
5246
env cldf.Environment,
5347
chain cldf_evm.Chain,
5448
ab cldf.AddressBook,
@@ -72,7 +66,7 @@ func DeployMCMSWithTimelockContractsEVM(
7266
callProxy = state.CallProxy
7367
}
7468
if bypasser == nil {
75-
seqInput := seqs.SeqDeployMCMWithConfigInput{
69+
seqInput := seqevm.SeqDeployMCMWithConfigInput{
7670
ContractType: mcmscontracts.BypasserManyChainMultisig,
7771
MCMConfig: config.Bypasser,
7872
ChainSelector: chain.Selector,
@@ -81,7 +75,7 @@ func DeployMCMSWithTimelockContractsEVM(
8175

8276
report, err := operations.ExecuteSequence(
8377
env.OperationsBundle,
84-
seqs.SeqEVMDeployMCMWithConfig,
78+
seqevm.SeqDeployMCMWithConfig,
8579
chain,
8680
seqInput,
8781
)
@@ -111,7 +105,7 @@ func DeployMCMSWithTimelockContractsEVM(
111105
}
112106

113107
if canceller == nil {
114-
seqInput := seqs.SeqDeployMCMWithConfigInput{
108+
seqInput := seqevm.SeqDeployMCMWithConfigInput{
115109
ContractType: mcmscontracts.CancellerManyChainMultisig,
116110
MCMConfig: config.Canceller,
117111
ChainSelector: chain.Selector,
@@ -120,7 +114,7 @@ func DeployMCMSWithTimelockContractsEVM(
120114

121115
report, err := operations.ExecuteSequence(
122116
env.OperationsBundle,
123-
seqs.SeqEVMDeployMCMWithConfig,
117+
seqevm.SeqDeployMCMWithConfig,
124118
chain,
125119
seqInput,
126120
)
@@ -150,7 +144,7 @@ func DeployMCMSWithTimelockContractsEVM(
150144
}
151145

152146
if proposer == nil {
153-
seqInput := seqs.SeqDeployMCMWithConfigInput{
147+
seqInput := seqevm.SeqDeployMCMWithConfigInput{
154148
ContractType: mcmscontracts.ProposerManyChainMultisig,
155149
MCMConfig: config.Proposer,
156150
ChainSelector: chain.Selector,
@@ -159,7 +153,7 @@ func DeployMCMSWithTimelockContractsEVM(
159153

160154
report, err := operations.ExecuteSequence(
161155
env.OperationsBundle,
162-
seqs.SeqEVMDeployMCMWithConfig,
156+
seqevm.SeqDeployMCMWithConfig,
163157
chain,
164158
seqInput,
165159
)
@@ -189,7 +183,7 @@ func DeployMCMSWithTimelockContractsEVM(
189183
}
190184

191185
if timelock == nil {
192-
opInput := opsevm.OpEVMDeployTimelockInput{
186+
opInput := opevm.OpDeployTimelockInput{
193187
// Deployer is the initial admin.
194188
// TODO: Could expose this as config?
195189
// Or keep this enforced to follow the same pattern?
@@ -205,13 +199,13 @@ func DeployMCMSWithTimelockContractsEVM(
205199

206200
report, err := operations.ExecuteOperation(
207201
env.OperationsBundle,
208-
opsevm.OpEVMDeployTimelock,
202+
opevm.OpDeployTimelock,
209203
chain,
210-
opsevm.EVMDeployInput[opsevm.OpEVMDeployTimelockInput]{
204+
oputils.EVMDeployInput[opevm.OpDeployTimelockInput]{
211205
ChainSelector: chain.Selector,
212206
DeployInput: opInput,
213207
},
214-
opsevm.RetryDeploymentWithGasBoost[opsevm.OpEVMDeployTimelockInput](config.GasBoostConfig),
208+
oputils.RetryDeploymentWithGasBoost[opevm.OpDeployTimelockInput](config.GasBoostConfig),
215209
)
216210
execReports = append(execReports, report.ToGenericReport())
217211
if err != nil {
@@ -240,19 +234,19 @@ func DeployMCMSWithTimelockContractsEVM(
240234
}
241235

242236
if callProxy == nil {
243-
opInput := opsevm.OpEVMDeployCallProxyInput{
237+
opInput := opevm.OpDeployCallProxyInput{
244238
Timelock: timelock.Address(),
245239
}
246240

247241
report, err := operations.ExecuteOperation(
248242
env.OperationsBundle,
249-
opsevm.OpEVMDeployCallProxy,
243+
opevm.OpDeployCallProxy,
250244
chain,
251-
opsevm.EVMDeployInput[opsevm.OpEVMDeployCallProxyInput]{
245+
oputils.EVMDeployInput[opevm.OpDeployCallProxyInput]{
252246
ChainSelector: chain.Selector,
253247
DeployInput: opInput,
254248
},
255-
opsevm.RetryDeploymentWithGasBoost[opsevm.OpEVMDeployCallProxyInput](config.GasBoostConfig),
249+
oputils.RetryDeploymentWithGasBoost[opevm.OpDeployCallProxyInput](config.GasBoostConfig),
256250
)
257251
execReports = append(execReports, report.ToGenericReport())
258252
if err != nil {
@@ -295,125 +289,3 @@ func DeployMCMSWithTimelockContractsEVM(
295289
// we can remove the deployer as an admin.
296290
return execReports, nil
297291
}
298-
299-
// TODO: delete this function after it is available in timelock Inspector
300-
func getAdminAddresses(ctx context.Context, timelock *bindings.RBACTimelock) ([]string, error) {
301-
numAddresses, err := timelock.GetRoleMemberCount(&bind.CallOpts{
302-
Context: ctx,
303-
}, mcmsrole.AdminRole.ID)
304-
if err != nil {
305-
return nil, err
306-
}
307-
adminAddresses := make([]string, 0, numAddresses.Uint64())
308-
for i := range numAddresses.Uint64() {
309-
if i > math.MaxUint32 {
310-
return nil, fmt.Errorf("value %d exceeds uint32 range", i)
311-
}
312-
idx, err := cast.ToInt64E(i)
313-
if err != nil {
314-
return nil, err
315-
}
316-
address, err := timelock.GetRoleMember(&bind.CallOpts{
317-
Context: ctx,
318-
}, mcmsrole.AdminRole.ID, big.NewInt(idx))
319-
if err != nil {
320-
return nil, err
321-
}
322-
adminAddresses = append(adminAddresses, address.String())
323-
}
324-
325-
return adminAddresses, nil
326-
}
327-
328-
func GrantRolesForTimelock(
329-
env cldf.Environment,
330-
chain cldf_evm.Chain,
331-
timelockContracts *cldfproposalutils.MCMSWithTimelockContracts,
332-
skipIfDeployerKeyNotAdmin bool, // If true, skip role grants if the deployer key is not an admin.
333-
gasBoostConfig *cldfproposalutils.GasBoostConfig,
334-
) (operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput], error) {
335-
lggr := env.Logger
336-
ctx := env.GetContext()
337-
338-
if timelockContracts == nil {
339-
lggr.Errorw("Timelock contracts not found", "chain", chain.String())
340-
return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, fmt.Errorf("timelock contracts not found for chain %s", chain.String())
341-
}
342-
343-
timelock := timelockContracts.Timelock
344-
proposer := timelockContracts.ProposerMcm
345-
canceller := timelockContracts.CancellerMcm
346-
bypasser := timelockContracts.BypasserMcm
347-
callProxy := timelockContracts.CallProxy
348-
349-
// get admin addresses
350-
adminAddresses, err := getAdminAddresses(ctx, timelock)
351-
if err != nil {
352-
return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, fmt.Errorf("failed to get admin addresses: %w", err)
353-
}
354-
isDeployerKeyAdmin := slices.Contains(adminAddresses, chain.DeployerKey.From.String())
355-
isTimelockAdmin := slices.Contains(adminAddresses, timelock.Address().String())
356-
if !isDeployerKeyAdmin && skipIfDeployerKeyNotAdmin {
357-
lggr.Infow("Deployer key is not admin, skipping role grants", "chain", chain.String())
358-
return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, nil
359-
}
360-
if !isDeployerKeyAdmin && !isTimelockAdmin {
361-
return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, errors.New("neither deployer key nor timelock is admin, cannot grant roles")
362-
}
363-
364-
seqDeps := seqs.SeqGrantRolesTimelockDeps{
365-
Chain: chain,
366-
}
367-
368-
seqInput := seqs.SeqGrantRolesTimelockInput{
369-
ContractType: mcmscontracts.RBACTimelock,
370-
ChainSelector: chain.Selector,
371-
Timelock: timelock.Address(),
372-
IsDeployerKeyAdmin: isDeployerKeyAdmin,
373-
RolesAndAddresses: []seqs.RolesAndAddresses{
374-
{
375-
Role: mcmsrole.ProposerRole.ID,
376-
Name: mcmsrole.ProposerRole.Name,
377-
Addresses: []common.Address{proposer.Address()},
378-
},
379-
{
380-
Role: mcmsrole.CancellerRole.ID,
381-
Name: mcmsrole.CancellerRole.Name,
382-
Addresses: []common.Address{proposer.Address(), canceller.Address(), bypasser.Address()},
383-
},
384-
{
385-
Role: mcmsrole.BypasserRole.ID,
386-
Name: mcmsrole.BypasserRole.Name,
387-
Addresses: []common.Address{bypasser.Address()},
388-
},
389-
{
390-
Role: mcmsrole.ExecutorRole.ID,
391-
Name: mcmsrole.ExecutorRole.Name,
392-
Addresses: []common.Address{callProxy.Address()},
393-
},
394-
},
395-
GasBoostConfig: gasBoostConfig,
396-
}
397-
398-
if !isTimelockAdmin {
399-
// We grant the timelock the admin role on the MCMS contracts.
400-
seqInput.RolesAndAddresses = append(seqInput.RolesAndAddresses, seqs.RolesAndAddresses{
401-
Role: mcmsrole.AdminRole.ID,
402-
Name: mcmsrole.AdminRole.Name,
403-
Addresses: []common.Address{timelock.Address()},
404-
})
405-
}
406-
407-
report, err := operations.ExecuteSequence(
408-
env.OperationsBundle,
409-
seqs.SeqGrantRolesTimelock,
410-
seqDeps,
411-
seqInput,
412-
)
413-
if err != nil {
414-
lggr.Errorw("Failed to grant roles for timelock", "chain", chain.String(), "err", err)
415-
return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, err
416-
}
417-
418-
return report, nil
419-
}

0 commit comments

Comments
 (0)