@@ -8,13 +8,58 @@ import (
88 "github.com/gagliardetto/solana-go"
99 signer_registry "github.com/smartcontractkit/ccip-base/chains/solana/go_bindings"
1010 "github.com/smartcontractkit/chainlink/deployment/common/proposalutils"
11+ "github.com/smartcontractkit/mcms"
12+ mcmsTypes "github.com/smartcontractkit/mcms/types"
1113
14+ cldf_solana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana"
1215 cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
1316 cs_solana "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/solana_v0_1_1"
1417 "github.com/smartcontractkit/chainlink/deployment/ccip/shared"
1518 solanastateview "github.com/smartcontractkit/chainlink/deployment/ccip/shared/stateview/solana"
1619)
1720
21+ // ExecuteOrBuildMCMSProposal handles the decision to execute instructions directly or build an MCMS proposal.
22+ // If mcmsConfig is nil, it executes the instructions directly on the chain.
23+ // If mcmsConfig is provided, it builds MCMS transactions and creates a proposal.
24+ func ExecuteOrBuildMCMSProposal (
25+ e cldf.Environment ,
26+ chain * cldf_solana.Chain ,
27+ instructions []solana.Instruction ,
28+ programID string ,
29+ contractType cldf.ContractType ,
30+ mcmsConfig * proposalutils.TimelockConfig ,
31+ proposalDescription string ,
32+ ) (cldf.ChangesetOutput , error ) {
33+ if mcmsConfig == nil {
34+ // Direct execution - confirm each instruction individually to avoid Tx size limits
35+ for i , ixn := range instructions {
36+ if err := chain .Confirm ([]solana.Instruction {ixn }); err != nil {
37+ return cldf.ChangesetOutput {}, fmt .Errorf ("failed to confirm instruction %d: %w" , i , err )
38+ }
39+ }
40+ return cldf.ChangesetOutput {}, nil
41+ }
42+
43+ mcmsTxns := make ([]mcmsTypes.Transaction , 0 , len (instructions ))
44+ for _ , ixn := range instructions {
45+ tx , err := cs_solana .BuildMCMSTxn (ixn , programID , contractType )
46+ if err != nil {
47+ return cldf.ChangesetOutput {}, fmt .Errorf ("failed to create MCMS transaction: %w" , err )
48+ }
49+ mcmsTxns = append (mcmsTxns , * tx )
50+ }
51+
52+ proposal , err := cs_solana .BuildProposalsForTxns (
53+ e , chain .Selector , proposalDescription , mcmsConfig .MinDelay , mcmsTxns )
54+ if err != nil {
55+ return cldf.ChangesetOutput {}, fmt .Errorf ("failed to build proposal: %w" , err )
56+ }
57+
58+ return cldf.ChangesetOutput {
59+ MCMSTimelockProposals : []mcms.TimelockProposal {* proposal },
60+ }, nil
61+ }
62+
1863// use this changeset to rotate NOPs (entirely remove addresses or add new ones)
1964var _ cldf.ChangeSet [RotateBaseSignerNopsConfig ] = RotateBaseSignerNopsChangeset
2065
@@ -54,7 +99,8 @@ type PromoteKeysConfig struct {
5499type SetUpgradeAuthorityConfig struct {
55100 ChainSelector uint64
56101 NewUpgradeAuthority solana.PublicKey
57- MCMS * proposalutils.TimelockConfig // if set, assumes current upgrade authority is the timelock
102+ // if set, assumes current upgrade authority is the timelock
103+ MCMS * proposalutils.TimelockConfig
58104}
59105
60106func RotateBaseSignerNopsChangeset (e cldf.Environment , c RotateBaseSignerNopsConfig ) (cldf.ChangesetOutput , error ) {
@@ -66,29 +112,35 @@ func RotateBaseSignerNopsChangeset(e cldf.Environment, c RotateBaseSignerNopsCon
66112 signersPda , _ , _ := solana .FindProgramAddress ([][]byte {[]byte ("signers" )}, signer_registry .ProgramID )
67113 eventAuthorityPda , _ , _ := solana .FindProgramAddress ([][]byte {[]byte ("__event_authority" )}, signer_registry .ProgramID )
68114
115+ var instructions []solana.Instruction
116+
69117 for _ , hexKey := range c .NopKeysToRemove {
70118 key , _ := parseEVMAddress (hexKey )
71119
72120 ix , err := signer_registry .NewRemoveSignerInstruction (key , chain .DeployerKey .PublicKey (), configPda , signersPda , eventAuthorityPda , signer_registry .ProgramID )
73121 if err != nil {
74122 return cldf.ChangesetOutput {}, fmt .Errorf ("Failed to remove signer: %w" , err )
75123 }
76- if err := chain .Confirm ([]solana.Instruction {ix }); err != nil {
77- return cldf.ChangesetOutput {}, fmt .Errorf ("Failed to remove signer: %w" , err )
78- }
124+ instructions = append (instructions , ix )
79125 }
80126 for _ , hexKey := range c .NopKeysToAdd {
81127 key , _ := parseEVMAddress (hexKey )
82128 ix , err := signer_registry .NewAddSignerInstruction (key , chain .DeployerKey .PublicKey (), configPda , signersPda , eventAuthorityPda , signer_registry .ProgramID )
83129 if err != nil {
84130 return cldf.ChangesetOutput {}, fmt .Errorf ("Failed to add signer: %w" , err )
85131 }
86- if err := chain .Confirm ([]solana.Instruction {ix }); err != nil {
87- return cldf.ChangesetOutput {}, fmt .Errorf ("Failed to add signer: %w" , err )
88- }
132+ instructions = append (instructions , ix )
89133 }
90134
91- return cldf.ChangesetOutput {}, nil
135+ return ExecuteOrBuildMCMSProposal (
136+ e ,
137+ & chain ,
138+ instructions ,
139+ signer_registry .ProgramID .String (),
140+ cldf .ContractType ("BaseSignerRegistry" ),
141+ c .MCMS ,
142+ "proposal to rotate attestation signer NOPs in Solana" ,
143+ )
92144}
93145
94146func (c RotateBaseSignerNopsConfig ) Validate (e cldf.Environment ) error {
@@ -160,6 +212,8 @@ func AddGreenKeysChangeset(e cldf.Environment, c AddGreenKeysConfig) (cldf.Chang
160212 signersPda , _ , _ := solana .FindProgramAddress ([][]byte {[]byte ("signers" )}, signer_registry .ProgramID )
161213 eventAuthorityPda , _ , _ := solana .FindProgramAddress ([][]byte {[]byte ("__event_authority" )}, signer_registry .ProgramID )
162214
215+ var instructions []solana.Instruction
216+
163217 for _ , keyPair := range c .BlueGreenKeys {
164218 blue , _ := parseEVMAddress (keyPair [0 ])
165219 green , _ := parseEVMAddress (keyPair [1 ])
@@ -168,12 +222,18 @@ func AddGreenKeysChangeset(e cldf.Environment, c AddGreenKeysConfig) (cldf.Chang
168222 if err != nil {
169223 return cldf.ChangesetOutput {}, fmt .Errorf ("Failed to add green key: %w" , err )
170224 }
171- if err := chain .Confirm ([]solana.Instruction {ix }); err != nil {
172- return cldf.ChangesetOutput {}, fmt .Errorf ("Failed to add green key: %w" , err )
173- }
225+ instructions = append (instructions , ix )
174226 }
175227
176- return cldf.ChangesetOutput {}, nil
228+ return ExecuteOrBuildMCMSProposal (
229+ e ,
230+ & chain ,
231+ instructions ,
232+ signer_registry .ProgramID .String (),
233+ cldf .ContractType ("BaseSignerRegistry" ),
234+ c .MCMS ,
235+ "proposal to add green keys for rotation in Solana" ,
236+ )
177237}
178238
179239func (c AddGreenKeysConfig ) Validate (e cldf.Environment ) error {
@@ -239,19 +299,27 @@ func PromoteKeysChangeset(e cldf.Environment, c PromoteKeysConfig) (cldf.Changes
239299 signersPda , _ , _ := solana .FindProgramAddress ([][]byte {[]byte ("signers" )}, signer_registry .ProgramID )
240300 eventAuthorityPda , _ , _ := solana .FindProgramAddress ([][]byte {[]byte ("__event_authority" )}, signer_registry .ProgramID )
241301
302+ var instructions []solana.Instruction
303+
242304 for _ , keyHex := range c .KeysToPromote {
243305 key , _ := parseEVMAddress (keyHex )
244306
245307 ix , err := signer_registry .NewPromoteSignerAddressInstruction (key , chain .DeployerKey .PublicKey (), configPda , signersPda , eventAuthorityPda , signer_registry .ProgramID )
246308 if err != nil {
247309 return cldf.ChangesetOutput {}, fmt .Errorf ("Failed to promote key: %w" , err )
248310 }
249- if err := chain .Confirm ([]solana.Instruction {ix }); err != nil {
250- return cldf.ChangesetOutput {}, fmt .Errorf ("Failed to promote key: %w" , err )
251- }
311+ instructions = append (instructions , ix )
252312 }
253313
254- return cldf.ChangesetOutput {}, nil
314+ return ExecuteOrBuildMCMSProposal (
315+ e ,
316+ & chain ,
317+ instructions ,
318+ signer_registry .ProgramID .String (),
319+ cldf .ContractType ("BaseSignerRegistry" ),
320+ c .MCMS ,
321+ "proposal to promote green keys in Solana" ,
322+ )
255323}
256324
257325func (c PromoteKeysConfig ) Validate (e cldf.Environment ) error {
@@ -303,11 +371,18 @@ func SetUpgradeAuthorityChangeset(
303371 chain := e .BlockChains .SolanaChains ()[config .ChainSelector ]
304372 currentAuthority := chain .DeployerKey .PublicKey ()
305373 e .Logger .Infow ("Setting upgrade authority" , "newUpgradeAuthority" , config .NewUpgradeAuthority .String ())
374+
306375 ixn := cs_solana .SetUpgradeAuthority (& e , & chain , signer_registry .ProgramID , currentAuthority , config .NewUpgradeAuthority , false )
307- if err := chain .Confirm ([]solana.Instruction {ixn }); err != nil {
308- return cldf.ChangesetOutput {}, fmt .Errorf ("failed to confirm instructions: %w" , err )
309- }
310- return cldf.ChangesetOutput {}, nil
376+
377+ return ExecuteOrBuildMCMSProposal (
378+ e ,
379+ & chain ,
380+ []solana.Instruction {ixn },
381+ solana .BPFLoaderUpgradeableProgramID .String (),
382+ cldf .ContractType (solana .BPFLoaderUpgradeableProgramID .String ()),
383+ config .MCMS ,
384+ "proposal to SetUpgradeAuthority in Solana" ,
385+ )
311386}
312387
313388func parseEVMAddress (addr string ) ([20 ]uint8 , error ) {
0 commit comments