diff --git a/governance/xc_admin/packages/xc_admin_cli/src/index.ts b/governance/xc_admin/packages/xc_admin_cli/src/index.ts index a6f2c2cb..710d9cc2 100644 --- a/governance/xc_admin/packages/xc_admin_cli/src/index.ts +++ b/governance/xc_admin/packages/xc_admin_cli/src/index.ts @@ -352,4 +352,68 @@ multisigCommand("activate", "Activate a transaction sitting in the multisig") await vault.squad.activateTransaction(transaction); }); +multisigCommand("add-and-delete", "Change the roster of the multisig") + .option( + "-a, --add ", + "addresses to add to the multisig" + ) + .option( + "-r, --remove ", + "addresses to remove from the multisig" + ) + .requiredOption( + "-t, --target-vaults ", + "the vault whose roster we want to change" + ) + .action(async (options: any) => { + const vault: MultisigVault = await loadVaultFromOptions(options); + + const targetVaults: PublicKey[] = options.targetVaults + ? options.targetVaults.split(",").map((m: string) => new PublicKey(m)) + : []; + + let proposalInstructions: TransactionInstruction[] = []; + + const membersToAdd: PublicKey[] = options.add + ? options.add.split(",").map((m: string) => new PublicKey(m)) + : []; + + for (const member of membersToAdd) { + for (const targetVault of targetVaults) { + proposalInstructions.push(await vault.addMemberIx(member, targetVault)); + } + } + + const membersToRemove: PublicKey[] = options.remove + ? options.remove.split(",").map((m: string) => new PublicKey(m)) + : []; + + for (const member of membersToRemove) { + for (const targetVault of targetVaults) { + proposalInstructions.push( + await vault.removeMemberIx(member, targetVault) + ); + } + } + + vault.proposeInstructions(proposalInstructions, options.cluster); + }); + +/** + * READ THIS BEFORE USING THIS COMMAND + * This command exists because of a bug in mesh where + * roster change proposals executed through executeInstruction don't work. + * It is equivalent to executing proposals through the mesh UI. + * It might not work for some types of proposals that require the crank to + * execute them. + * https://github.com/Squads-Protocol/squads-mpl/pull/32 + */ +multisigCommand("execute-add-and-delete", "Execute a roster change proposal") + .requiredOption("-t, --transaction ", "address of the proposal") + .action(async (options: any) => { + const vault: MultisigVault = await loadVaultFromOptions(options); + const proposal = new PublicKey(options.transaction); + await vault.squad.executeTransaction(proposal); + }); + program.parse(); diff --git a/governance/xc_admin/packages/xc_admin_common/src/propose.ts b/governance/xc_admin/packages/xc_admin_common/src/propose.ts index 5346820a..34579340 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/propose.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/propose.ts @@ -147,6 +147,28 @@ export class MultisigVault { ); } + public async addMemberIx( + member: PublicKey, + targetVault: PublicKey + ): Promise { + return await this.squad.buildAddMember( + targetVault, + await this.getAuthorityPDA(), + member + ); + } + + public async removeMemberIx( + member: PublicKey, + targetVault: PublicKey + ): Promise { + return await this.squad.buildRemoveMember( + targetVault, + await this.getAuthorityPDA(), + member + ); + } + // Propose instructions /** diff --git a/package-lock.json b/package-lock.json index 1fc2fb45..947d16fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55756,7 +55756,7 @@ }, "price_pusher": { "name": "@pythnetwork/price-pusher", - "version": "5.3.0", + "version": "5.3.1", "license": "Apache-2.0", "dependencies": { "@injectivelabs/sdk-ts": "1.10.72",