Răsfoiți Sursa

feat(governance/xc_admin): add initial support for solana receiver (#1365)

* feat(governance/xc_admin): add initial support for solana receiver

This change adds Solana Receiver IDL to xc-admin to support parsing
them in the xc-admin Frontend. Also adds two CLI commands to request
and accept governance authority transfer.

* chore: address comments

* chore: bump version
Ali Behjati 1 an în urmă
părinte
comite
ab7560ad35

+ 2 - 1
governance/xc_admin/packages/xc_admin_cli/package.json

@@ -28,6 +28,7 @@
     "@sqds/mesh": "^1.0.6",
     "commander": "^9.5.0",
     "typescript": "^4.9.4",
-    "xc_admin_common": "*"
+    "xc_admin_common": "*",
+    "@pythnetwork/pyth-solana-receiver": "*"
   }
 }

+ 63 - 1
governance/xc_admin/packages/xc_admin_cli/src/index.ts

@@ -36,6 +36,13 @@ import {
   getMultisigCluster,
   getProposalInstructions,
 } from "xc_admin_common";
+
+import {
+  pythSolanaReceiverIdl,
+  getConfigPda,
+  DEFAULT_RECEIVER_PROGRAM_ID,
+} from "@pythnetwork/pyth-solana-receiver";
+
 import { LedgerNodeWallet } from "./ledger";
 
 export async function loadHotWalletOrLedger(
@@ -102,7 +109,7 @@ program
   .version("0.1.0");
 
 multisigCommand(
-  "accept-authority",
+  "escrow-program-accept-authority",
   "Accept authority from the program authority escrow"
 )
   .requiredOption(
@@ -150,6 +157,61 @@ multisigCommand(
     await vault.proposeInstructions([proposalInstruction], targetCluster);
   });
 
+multisigCommand(
+  "solana-receiver-program-accept-governance-authority-transfer",
+  "Accept governance authority transfer for the solana receiver program"
+).action(async (options: any) => {
+  const vault = await loadVaultFromOptions(options);
+  const targetCluster: PythCluster = options.cluster;
+
+  const programSolanaReceiver = new Program(
+    pythSolanaReceiverIdl,
+    DEFAULT_RECEIVER_PROGRAM_ID,
+    vault.getAnchorProvider()
+  );
+
+  const proposalInstruction = await programSolanaReceiver.methods
+    .acceptGovernanceAuthorityTransfer()
+    .accounts({
+      payer: await vault.getVaultAuthorityPDA(targetCluster),
+      config: getConfigPda(DEFAULT_RECEIVER_PROGRAM_ID),
+    })
+    .instruction();
+
+  await vault.proposeInstructions([proposalInstruction], targetCluster);
+});
+
+multisigCommand(
+  "solana-receiver-program-request-governance-authority-transfer",
+  "Request governance authority transfer for the solana receiver program"
+)
+  .requiredOption(
+    "-t, --target <pubkey>",
+    "The new governance authority to take over. " +
+      "If the target is another multisig, it will be the multisig's vault authority PDA."
+  )
+  .action(async (options: any) => {
+    const vault = await loadVaultFromOptions(options);
+    const targetCluster: PythCluster = options.cluster;
+    const target: PublicKey = new PublicKey(options.target);
+
+    const programSolanaReceiver = new Program(
+      pythSolanaReceiverIdl,
+      DEFAULT_RECEIVER_PROGRAM_ID,
+      vault.getAnchorProvider()
+    );
+
+    const proposalInstruction = await programSolanaReceiver.methods
+      .requestGovernanceAuthorityTransfer(target)
+      .accounts({
+        payer: await vault.getVaultAuthorityPDA(targetCluster),
+        config: getConfigPda(DEFAULT_RECEIVER_PROGRAM_ID),
+      })
+      .instruction();
+
+    await vault.proposeInstructions([proposalInstruction], targetCluster);
+  });
+
 multisigCommand("upgrade-program", "Upgrade a program from a buffer")
   .requiredOption(
     "-p, --program-id <pubkey>",

+ 2 - 1
governance/xc_admin/packages/xc_admin_common/package.json

@@ -30,7 +30,8 @@
     "ethers": "^5.7.2",
     "lodash": "^4.17.21",
     "typescript": "^4.9.4",
-    "@pythnetwork/solana-utils": "*"
+    "@pythnetwork/solana-utils": "*",
+    "@pythnetwork/pyth-solana-receiver": "*"
   },
   "devDependencies": {
     "@types/bn.js": "^5.1.1",

+ 8 - 0
governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/MessageBufferMultisigInstruction.ts

@@ -11,6 +11,10 @@ import { Idl, BorshCoder } from "@coral-xyz/anchor";
 import { MESSAGE_BUFFER_PROGRAM_ID } from "../message_buffer";
 import meshIdl from "@sqds/mesh/lib/mesh-idl/mesh.json";
 import stakingIdl from "./idl/staking.json";
+import {
+  DEFAULT_RECEIVER_PROGRAM_ID,
+  pythSolanaReceiverIdl,
+} from "@pythnetwork/pyth-solana-receiver";
 
 export const MESH_PROGRAM_ID = new PublicKey(
   "SMPLVC8MxZ5Bf5EfF7PaMiTCxoBAcmkbM2vkrvMK8ho"
@@ -55,6 +59,10 @@ export class AnchorMultisigInstruction implements MultisigInstruction {
         idl = stakingIdl as Idl;
         program = MultisigInstructionProgram.Staking;
         break;
+      case DEFAULT_RECEIVER_PROGRAM_ID.toBase58():
+        idl = pythSolanaReceiverIdl as Idl;
+        program = MultisigInstructionProgram.SolanaReceiver;
+        break;
       default:
         return UnrecognizedProgram.fromTransactionInstruction(instruction);
     }

+ 6 - 1
governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts

@@ -22,6 +22,7 @@ import { BpfUpgradableLoaderInstruction } from "./BpfUpgradableLoaderMultisigIns
 import { BPF_UPGRADABLE_LOADER } from "../bpf_upgradable_loader";
 import { AnchorAccounts } from "./anchor";
 import { SolanaStakingMultisigInstruction } from "./SolanaStakingMultisigInstruction";
+import { DEFAULT_RECEIVER_PROGRAM_ID } from "@pythnetwork/pyth-solana-receiver";
 
 export const UNRECOGNIZED_INSTRUCTION = "unrecognizedInstruction";
 export enum MultisigInstructionProgram {
@@ -33,6 +34,7 @@ export enum MultisigInstructionProgram {
   SystemProgram,
   BpfUpgradableLoader,
   SolanaStakingProgram,
+  SolanaReceiver,
   UnrecognizedProgram,
 }
 
@@ -54,6 +56,8 @@ export function getProgramName(program: MultisigInstructionProgram) {
       return "Mesh Multisig Program";
     case MultisigInstructionProgram.Staking:
       return "Pyth Staking Program";
+    case MultisigInstructionProgram.SolanaReceiver:
+      return "Pyth Solana Receiver";
     case MultisigInstructionProgram.UnrecognizedProgram:
       return "Unknown";
   }
@@ -123,7 +127,8 @@ export class MultisigParser {
     } else if (
       instruction.programId.equals(MESSAGE_BUFFER_PROGRAM_ID) ||
       instruction.programId.equals(MESH_PROGRAM_ID) ||
-      instruction.programId.equals(STAKING_PROGRAM_ID)
+      instruction.programId.equals(STAKING_PROGRAM_ID) ||
+      instruction.programId.equals(DEFAULT_RECEIVER_PROGRAM_ID)
     ) {
       return AnchorMultisigInstruction.fromTransactionInstruction(instruction);
     } else if (instruction.programId.equals(SystemProgram.programId)) {

+ 10 - 12
package-lock.json

@@ -658,6 +658,7 @@
         "isomorphic-ws": "^5.0.0",
         "openapi-client-axios": "^7.5.4",
         "openapi-fetch": "^0.8.2",
+        "openapi-typescript": "^6.5.5",
         "viem": "^2.7.6",
         "ws": "^8.16.0"
       },
@@ -667,9 +668,8 @@
         "@typescript-eslint/parser": "^5.21.0",
         "eslint": "^8.56.0",
         "jest": "^27.5.1",
-        "openapi-typescript": "^6.5.5",
         "prettier": "^2.6.2",
-        "typescript": "^5.1",
+        "typescript": "^5.3.3",
         "yargs": "^17.4.1"
       }
     },
@@ -1882,7 +1882,6 @@
       "version": "6.5.5",
       "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.5.5.tgz",
       "integrity": "sha512-pMsA8GrMQKtNOPPjKnJbDotA2UpKsIcTHecMw2Bl3M/2eWTVs8zAYBm/cgaE9Qz5GrcVCDIru9GQX/P9vxtUFg==",
-      "dev": true,
       "dependencies": {
         "ansi-colors": "^4.1.3",
         "fast-glob": "^3.3.1",
@@ -1899,7 +1898,6 @@
       "version": "9.4.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
       "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
-      "dev": true,
       "engines": {
         "node": ">=12"
       },
@@ -2126,7 +2124,6 @@
       "version": "21.1.1",
       "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
       "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-      "dev": true,
       "engines": {
         "node": ">=12"
       }
@@ -3373,6 +3370,7 @@
         "@ledgerhq/hw-transport": "^6.27.10",
         "@ledgerhq/hw-transport-node-hid": "^6.27.10",
         "@pythnetwork/client": "^2.9.0",
+        "@pythnetwork/pyth-solana-receiver": "*",
         "@solana/web3.js": "^1.73.0",
         "@sqds/mesh": "^1.0.6",
         "commander": "^9.5.0",
@@ -3395,6 +3393,7 @@
         "@certusone/wormhole-sdk": "^0.9.22",
         "@coral-xyz/anchor": "^0.29.0",
         "@pythnetwork/client": "^2.17.0",
+        "@pythnetwork/pyth-solana-receiver": "*",
         "@pythnetwork/solana-utils": "*",
         "@solana/buffer-layout": "^4.0.1",
         "@solana/web3.js": "^1.73.0",
@@ -59294,7 +59293,7 @@
     },
     "target_chains/solana/sdk/js/pyth_solana_receiver": {
       "name": "@pythnetwork/pyth-solana-receiver",
-      "version": "0.2.2",
+      "version": "0.2.3",
       "license": "Apache-2.0",
       "dependencies": {
         "@coral-xyz/anchor": "^0.29.0",
@@ -67914,7 +67913,7 @@
         "openapi-fetch": "^0.8.2",
         "openapi-typescript": "^6.5.5",
         "prettier": "^2.6.2",
-        "typescript": "^5.1",
+        "typescript": "^5.3.3",
         "viem": "^2.7.6",
         "ws": "^8.16.0",
         "yargs": "^17.4.1"
@@ -68844,7 +68843,6 @@
           "version": "6.5.5",
           "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.5.5.tgz",
           "integrity": "sha512-pMsA8GrMQKtNOPPjKnJbDotA2UpKsIcTHecMw2Bl3M/2eWTVs8zAYBm/cgaE9Qz5GrcVCDIru9GQX/P9vxtUFg==",
-          "dev": true,
           "requires": {
             "ansi-colors": "^4.1.3",
             "fast-glob": "^3.3.1",
@@ -68857,8 +68855,7 @@
             "supports-color": {
               "version": "9.4.0",
               "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
-              "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
-              "dev": true
+              "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw=="
             }
           }
         },
@@ -69002,8 +68999,7 @@
         "yargs-parser": {
           "version": "21.1.1",
           "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-          "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-          "dev": true
+          "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
         }
       }
     },
@@ -105661,6 +105657,7 @@
         "@ledgerhq/hw-transport": "^6.27.10",
         "@ledgerhq/hw-transport-node-hid": "^6.27.10",
         "@pythnetwork/client": "^2.9.0",
+        "@pythnetwork/pyth-solana-receiver": "*",
         "@solana/web3.js": "^1.73.0",
         "@sqds/mesh": "^1.0.6",
         "commander": "^9.5.0",
@@ -105681,6 +105678,7 @@
         "@certusone/wormhole-sdk": "^0.9.22",
         "@coral-xyz/anchor": "^0.29.0",
         "@pythnetwork/client": "^2.17.0",
+        "@pythnetwork/pyth-solana-receiver": "*",
         "@pythnetwork/solana-utils": "*",
         "@solana/buffer-layout": "^4.0.1",
         "@solana/web3.js": "^1.73.0",

+ 1 - 1
target_chains/solana/sdk/js/pyth_solana_receiver/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/pyth-solana-receiver",
-  "version": "0.2.2",
+  "version": "0.2.3",
   "description": "Pyth solana receiver SDK",
   "homepage": "https://pyth.network",
   "main": "lib/index.js",

+ 16 - 0
target_chains/solana/sdk/js/pyth_solana_receiver/src/index.ts

@@ -6,3 +6,19 @@ export {
   TransactionBuilder,
   InstructionWithEphemeralSigners,
 } from "@pythnetwork/solana-utils";
+
+export {
+  getConfigPda,
+  DEFAULT_RECEIVER_PROGRAM_ID,
+  DEFAULT_WORMHOLE_PROGRAM_ID,
+} from "./address";
+
+export {
+  IDL as pythSolanaReceiverIdl,
+  PythSolanaReceiver as PythSolanaReceiverProgram,
+} from "./idl/pyth_solana_receiver";
+
+export {
+  IDL as wormholeCoreBridgeIdl,
+  WormholeCoreBridgeSolana as WormholeCoreBridgeProgram,
+} from "./idl/wormhole_core_bridge_solana";