@@ -180,6 +180,117 @@ program
180180 ) ;
181181 } ) ;
182182
183+ program
184+ . command ( "change-threshold" )
185+ . description ( "Change threshold of multisig" )
186+ . option ( "-c, --cluster <network>" , "solana cluster to use" , "devnet" )
187+ . requiredOption ( "-v, --vault-address <address>" , "multisig vault address" )
188+ . option ( "-l, --ledger" , "use ledger" )
189+ . option (
190+ "-lda, --ledger-derivation-account <number>" ,
191+ "ledger derivation account to use"
192+ )
193+ . option (
194+ "-ldc, --ledger-derivation-change <number>" ,
195+ "ledger derivation change to use"
196+ )
197+ . option (
198+ "-w, --wallet <filepath>" ,
199+ "multisig wallet secret key filepath" ,
200+ "keys/key.json"
201+ )
202+ . option ( "-t, --threshold <number>" , "new threshold" )
203+ . action ( async ( options ) => {
204+ const squad = await getSquadsClient (
205+ options . cluster ,
206+ options . ledger ,
207+ options . ledgerDerivationAccount ,
208+ options . ledgerDerivationChange ,
209+ options . wallet
210+ ) ;
211+ await changeThreshold (
212+ options . cluster ,
213+ squad ,
214+ options . ledger ,
215+ new PublicKey ( options . vaultAddress ) ,
216+ options . threshold
217+ ) ;
218+ } ) ;
219+
220+ program
221+ . command ( "add-member" )
222+ . description ( "Add member to multisig" )
223+ . option ( "-c, --cluster <network>" , "solana cluster to use" , "devnet" )
224+ . requiredOption ( "-v, --vault-address <address>" , "multisig vault address" )
225+ . option ( "-l, --ledger" , "use ledger" )
226+ . option (
227+ "-lda, --ledger-derivation-account <number>" ,
228+ "ledger derivation account to use"
229+ )
230+ . option (
231+ "-ldc, --ledger-derivation-change <number>" ,
232+ "ledger derivation change to use"
233+ )
234+ . option (
235+ "-w, --wallet <filepath>" ,
236+ "multisig wallet secret key filepath" ,
237+ "keys/key.json"
238+ )
239+ . option ( "-m, --member <address>" , "new member address" )
240+ . action ( async ( options ) => {
241+ const squad = await getSquadsClient (
242+ options . cluster ,
243+ options . ledger ,
244+ options . ledgerDerivationAccount ,
245+ options . ledgerDerivationChange ,
246+ options . wallet
247+ ) ;
248+ await addMember (
249+ options . cluster ,
250+ squad ,
251+ options . ledger ,
252+ new PublicKey ( options . vaultAddress ) ,
253+ new PublicKey ( options . member )
254+ ) ;
255+ } ) ;
256+
257+ program
258+ . command ( "remove-member" )
259+ . description ( "Remove member from multisig" )
260+ . option ( "-c, --cluster <network>" , "solana cluster to use" , "devnet" )
261+ . requiredOption ( "-v, --vault-address <address>" , "multisig vault address" )
262+ . option ( "-l, --ledger" , "use ledger" )
263+ . option (
264+ "-lda, --ledger-derivation-account <number>" ,
265+ "ledger derivation account to use"
266+ )
267+ . option (
268+ "-ldc, --ledger-derivation-change <number>" ,
269+ "ledger derivation change to use"
270+ )
271+ . option (
272+ "-w, --wallet <filepath>" ,
273+ "multisig wallet secret key filepath" ,
274+ "keys/key.json"
275+ )
276+ . option ( "-m, --member <address>" , "old member address" )
277+ . action ( async ( options ) => {
278+ const squad = await getSquadsClient (
279+ options . cluster ,
280+ options . ledger ,
281+ options . ledgerDerivationAccount ,
282+ options . ledgerDerivationChange ,
283+ options . wallet
284+ ) ;
285+ await removeMember (
286+ options . cluster ,
287+ squad ,
288+ options . ledger ,
289+ new PublicKey ( options . vaultAddress ) ,
290+ new PublicKey ( options . member )
291+ ) ;
292+ } ) ;
293+
183294// TODO: add subcommand for creating governance messages in the right format
184295
185296program . parse ( ) ;
@@ -548,6 +659,84 @@ async function executeMultisigTx(
548659 console . log ( `Payload: ${ Buffer . from ( parsedVaa . payload ) . toString ( "hex" ) } ` ) ;
549660}
550661
662+ async function changeThreshold (
663+ cluster : Cluster ,
664+ squad : Squads ,
665+ ledger : boolean ,
666+ vault : PublicKey ,
667+ threshold : number
668+ ) {
669+ const msAccount = await squad . getMultisig ( vault ) ;
670+ const txKey = await createTx ( squad , ledger , vault ) ;
671+ const ix = await squad . buildChangeThresholdMember (
672+ msAccount . publicKey ,
673+ msAccount . externalAuthority ,
674+ threshold
675+ ) ;
676+
677+ const squadIxs : SquadInstruction [ ] = [ { instruction : ix } ] ;
678+ await addInstructionsToTx (
679+ cluster ,
680+ squad ,
681+ ledger ,
682+ msAccount . publicKey ,
683+ txKey ,
684+ squadIxs
685+ ) ;
686+ }
687+
688+ async function addMember (
689+ cluster : Cluster ,
690+ squad : Squads ,
691+ ledger : boolean ,
692+ vault : PublicKey ,
693+ member : PublicKey
694+ ) {
695+ const msAccount = await squad . getMultisig ( vault ) ;
696+ const txKey = await createTx ( squad , ledger , vault ) ;
697+ const ix = await squad . buildAddMember (
698+ msAccount . publicKey ,
699+ msAccount . externalAuthority ,
700+ member
701+ ) ;
702+
703+ const squadIxs : SquadInstruction [ ] = [ { instruction : ix } ] ;
704+ await addInstructionsToTx (
705+ cluster ,
706+ squad ,
707+ ledger ,
708+ msAccount . publicKey ,
709+ txKey ,
710+ squadIxs
711+ ) ;
712+ }
713+
714+ async function removeMember (
715+ cluster : Cluster ,
716+ squad : Squads ,
717+ ledger : boolean ,
718+ vault : PublicKey ,
719+ member : PublicKey
720+ ) {
721+ const msAccount = await squad . getMultisig ( vault ) ;
722+ const txKey = await createTx ( squad , ledger , vault ) ;
723+ const ix = await squad . buildRemoveMember (
724+ msAccount . publicKey ,
725+ msAccount . externalAuthority ,
726+ member
727+ ) ;
728+
729+ const squadIxs : SquadInstruction [ ] = [ { instruction : ix } ] ;
730+ await addInstructionsToTx (
731+ cluster ,
732+ squad ,
733+ ledger ,
734+ msAccount . publicKey ,
735+ txKey ,
736+ squadIxs
737+ ) ;
738+ }
739+
551740async function parse ( data : string ) {
552741 const { parse_vaa } = await importCoreWasm ( ) ;
553742 return parse_vaa ( Uint8Array . from ( Buffer . from ( data , "base64" ) ) ) ;
0 commit comments