Ver código fonte

Add staking instructions to xc-admin (#1160)

* Do it

* Add xc-admin-cli command for proposing deactivate-stake instructions

* Cleanup

---------

Co-authored-by: Thomaz Leite <thomaz@pyth.network>
guibescos 2 anos atrás
pai
commit
57b1367b91

+ 30 - 0
governance/xc_admin/packages/xc_admin_cli/src/index.ts

@@ -5,6 +5,7 @@ import {
   SYSVAR_RENT_PUBKEY,
   SYSVAR_CLOCK_PUBKEY,
   AccountMeta,
+  StakeProgram,
   SystemProgram,
   LAMPORTS_PER_SOL,
   Connection,
@@ -226,6 +227,35 @@ multisigCommand(
     await vault.proposeInstructions([proposalInstruction], cluster);
   });
 
+multisigCommand(
+  "deactivate-stake",
+  "Deactivate the delegated stake from the account"
+)
+  .requiredOption(
+    "-s, --stake-accounts <accounts...>",
+    "stake accounts to be deactivated"
+  )
+  .action(async (options: any) => {
+    const vault = await loadVaultFromOptions(options);
+    const cluster: PythCluster = options.cluster;
+    const authorizedPubkey: PublicKey = await vault.getVaultAuthorityPDA(
+      cluster
+    );
+    const instructions = options.stakeAccounts.reduce(
+      (instructions: TransactionInstruction[], stakeAccount: string) => {
+        const transaction = StakeProgram.deactivate({
+          stakePubkey: new PublicKey(stakeAccount),
+          authorizedPubkey,
+        });
+
+        return instructions.concat(transaction.instructions);
+      },
+      []
+    );
+
+    await vault.proposeInstructions(instructions, cluster);
+  });
+
 multisigCommand(
   "init-price",
   "Init price (useful for changing the exponent), only to be used on unused price feeds"

+ 72 - 0
governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/SolanaStakingMultisigInstruction.ts

@@ -0,0 +1,72 @@
+import { TransactionInstruction } from "@solana/web3.js";
+import {
+  MultisigInstruction,
+  MultisigInstructionProgram,
+  UNRECOGNIZED_INSTRUCTION,
+} from ".";
+import { AnchorAccounts } from "./anchor";
+import { StakeInstruction } from "@solana/web3.js";
+
+export class SolanaStakingMultisigInstruction implements MultisigInstruction {
+  readonly program = MultisigInstructionProgram.SolanaStakingProgram;
+  readonly name: string;
+  readonly args: { [key: string]: any };
+  readonly accounts: AnchorAccounts;
+
+  constructor(
+    name: string,
+    args: { [key: string]: any },
+    accounts: AnchorAccounts
+  ) {
+    this.name = name;
+    this.args = args;
+    this.accounts = accounts;
+  }
+
+  static fromTransactionInstruction(
+    instruction: TransactionInstruction
+  ): SolanaStakingMultisigInstruction {
+    try {
+      const type = StakeInstruction.decodeInstructionType(instruction);
+      switch (type) {
+        case "Deactivate":
+          const decoded = StakeInstruction.decodeDeactivate(instruction);
+          return new SolanaStakingMultisigInstruction(
+            "Deactivate",
+            {},
+            {
+              named: {
+                stakePubkey: {
+                  pubkey: decoded.stakePubkey,
+                  isSigner: false,
+                  isWritable: true,
+                },
+                authorizedPubkey: {
+                  pubkey: decoded.authorizedPubkey,
+                  isSigner: true,
+                  isWritable: false,
+                },
+              },
+              remaining: [],
+            }
+          );
+
+        case "Authorize":
+        case "AuthorizeWithSeed":
+        case "Delegate":
+        case "Initialize":
+        case "Merge":
+        case "Split":
+        case "Withdraw":
+        case "Authorize":
+          throw Error("Unsupported instruction type");
+      }
+    } catch {
+      return new SolanaStakingMultisigInstruction(
+        UNRECOGNIZED_INSTRUCTION,
+        { data: instruction.data },
+        { named: {}, remaining: instruction.keys }
+      );
+    }
+  }
+}

+ 10 - 0
governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts

@@ -4,6 +4,7 @@ import {
 } from "@pythnetwork/client/lib/cluster";
 import {
   PublicKey,
+  StakeProgram,
   SystemProgram,
   TransactionInstruction,
 } from "@solana/web3.js";
@@ -16,6 +17,7 @@ import { SystemProgramMultisigInstruction } from "./SystemProgramInstruction";
 import { BpfUpgradableLoaderInstruction } from "./BpfUpgradableLoaderMultisigInstruction";
 import { BPF_UPGRADABLE_LOADER } from "../bpf_upgradable_loader";
 import { AnchorAccounts } from "./anchor";
+import { SolanaStakingMultisigInstruction } from "./SolanaStakingMultisigInstruction";
 
 export const UNRECOGNIZED_INSTRUCTION = "unrecognizedInstruction";
 export enum MultisigInstructionProgram {
@@ -24,6 +26,7 @@ export enum MultisigInstructionProgram {
   MessageBuffer,
   SystemProgram,
   BpfUpgradableLoader,
+  SolanaStakingProgram,
   UnrecognizedProgram,
 }
 
@@ -39,6 +42,8 @@ export function getProgramName(program: MultisigInstructionProgram) {
       return "System Program";
     case MultisigInstructionProgram.BpfUpgradableLoader:
       return "BPF Upgradable Loader";
+    case MultisigInstructionProgram.SolanaStakingProgram:
+      return "Solana Staking Program";
     case MultisigInstructionProgram.UnrecognizedProgram:
       return "Unknown";
   }
@@ -117,6 +122,10 @@ export class MultisigParser {
       return BpfUpgradableLoaderInstruction.fromTransactionInstruction(
         instruction
       );
+    } else if (instruction.programId.equals(StakeProgram.programId)) {
+      return SolanaStakingMultisigInstruction.fromTransactionInstruction(
+        instruction
+      );
     } else {
       return UnrecognizedProgram.fromTransactionInstruction(instruction);
     }
@@ -128,3 +137,4 @@ export { PythMultisigInstruction } from "./PythMultisigInstruction";
 export { MessageBufferMultisigInstruction } from "./MessageBufferMultisigInstruction";
 export { SystemProgramMultisigInstruction } from "./SystemProgramInstruction";
 export { BpfUpgradableLoaderInstruction } from "./BpfUpgradableLoaderMultisigInstruction";
+export { SolanaStakingMultisigInstruction } from "./SolanaStakingMultisigInstruction";