11package changesets
22
33import (
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