From b784abd144edc31c45c8de1fbca1897fe90aeb20 Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Thu, 20 Oct 2022 17:25:53 +0800 Subject: [PATCH] add change-threshold, add-member, and remove-member (#358) --- .../multisig-wh-message-builder/src/index.ts | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/third_party/pyth/multisig-wh-message-builder/src/index.ts b/third_party/pyth/multisig-wh-message-builder/src/index.ts index cc2254f5..49681bc9 100644 --- a/third_party/pyth/multisig-wh-message-builder/src/index.ts +++ b/third_party/pyth/multisig-wh-message-builder/src/index.ts @@ -180,6 +180,117 @@ program ); }); +program + .command("change-threshold") + .description("Change threshold of multisig") + .option("-c, --cluster ", "solana cluster to use", "devnet") + .requiredOption("-v, --vault-address
", "multisig vault address") + .option("-l, --ledger", "use ledger") + .option( + "-lda, --ledger-derivation-account ", + "ledger derivation account to use" + ) + .option( + "-ldc, --ledger-derivation-change ", + "ledger derivation change to use" + ) + .option( + "-w, --wallet ", + "multisig wallet secret key filepath", + "keys/key.json" + ) + .option("-t, --threshold ", "new threshold") + .action(async (options) => { + const squad = await getSquadsClient( + options.cluster, + options.ledger, + options.ledgerDerivationAccount, + options.ledgerDerivationChange, + options.wallet + ); + await changeThreshold( + options.cluster, + squad, + options.ledger, + new PublicKey(options.vaultAddress), + options.threshold + ); + }); + +program + .command("add-member") + .description("Add member to multisig") + .option("-c, --cluster ", "solana cluster to use", "devnet") + .requiredOption("-v, --vault-address
", "multisig vault address") + .option("-l, --ledger", "use ledger") + .option( + "-lda, --ledger-derivation-account ", + "ledger derivation account to use" + ) + .option( + "-ldc, --ledger-derivation-change ", + "ledger derivation change to use" + ) + .option( + "-w, --wallet ", + "multisig wallet secret key filepath", + "keys/key.json" + ) + .option("-m, --member
", "new member address") + .action(async (options) => { + const squad = await getSquadsClient( + options.cluster, + options.ledger, + options.ledgerDerivationAccount, + options.ledgerDerivationChange, + options.wallet + ); + await addMember( + options.cluster, + squad, + options.ledger, + new PublicKey(options.vaultAddress), + new PublicKey(options.member) + ); + }); + +program + .command("remove-member") + .description("Remove member from multisig") + .option("-c, --cluster ", "solana cluster to use", "devnet") + .requiredOption("-v, --vault-address
", "multisig vault address") + .option("-l, --ledger", "use ledger") + .option( + "-lda, --ledger-derivation-account ", + "ledger derivation account to use" + ) + .option( + "-ldc, --ledger-derivation-change ", + "ledger derivation change to use" + ) + .option( + "-w, --wallet ", + "multisig wallet secret key filepath", + "keys/key.json" + ) + .option("-m, --member
", "old member address") + .action(async (options) => { + const squad = await getSquadsClient( + options.cluster, + options.ledger, + options.ledgerDerivationAccount, + options.ledgerDerivationChange, + options.wallet + ); + await removeMember( + options.cluster, + squad, + options.ledger, + new PublicKey(options.vaultAddress), + new PublicKey(options.member) + ); + }); + // TODO: add subcommand for creating governance messages in the right format program.parse(); @@ -548,6 +659,84 @@ async function executeMultisigTx( console.log(`Payload: ${Buffer.from(parsedVaa.payload).toString("hex")}`); } +async function changeThreshold( + cluster: Cluster, + squad: Squads, + ledger: boolean, + vault: PublicKey, + threshold: number +) { + const msAccount = await squad.getMultisig(vault); + const txKey = await createTx(squad, ledger, vault); + const ix = await squad.buildChangeThresholdMember( + msAccount.publicKey, + msAccount.externalAuthority, + threshold + ); + + const squadIxs: SquadInstruction[] = [{ instruction: ix }]; + await addInstructionsToTx( + cluster, + squad, + ledger, + msAccount.publicKey, + txKey, + squadIxs + ); +} + +async function addMember( + cluster: Cluster, + squad: Squads, + ledger: boolean, + vault: PublicKey, + member: PublicKey +) { + const msAccount = await squad.getMultisig(vault); + const txKey = await createTx(squad, ledger, vault); + const ix = await squad.buildAddMember( + msAccount.publicKey, + msAccount.externalAuthority, + member + ); + + const squadIxs: SquadInstruction[] = [{ instruction: ix }]; + await addInstructionsToTx( + cluster, + squad, + ledger, + msAccount.publicKey, + txKey, + squadIxs + ); +} + +async function removeMember( + cluster: Cluster, + squad: Squads, + ledger: boolean, + vault: PublicKey, + member: PublicKey +) { + const msAccount = await squad.getMultisig(vault); + const txKey = await createTx(squad, ledger, vault); + const ix = await squad.buildRemoveMember( + msAccount.publicKey, + msAccount.externalAuthority, + member + ); + + const squadIxs: SquadInstruction[] = [{ instruction: ix }]; + await addInstructionsToTx( + cluster, + squad, + ledger, + msAccount.publicKey, + txKey, + squadIxs + ); +} + async function parse(data: string) { const { parse_vaa } = await importCoreWasm(); return parse_vaa(Uint8Array.from(Buffer.from(data, "base64")));