浏览代码

Refactor MultisigInstruction (#1098)

* Refactor unknown

* Cleanup

* Cleanup further
guibescos 2 年之前
父节点
当前提交
5c0c252cee

+ 37 - 4
governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts

@@ -15,6 +15,7 @@ import { WormholeMultisigInstruction } from "./WormholeMultisigInstruction";
 import { SystemProgramMultisigInstruction } from "./SystemProgramInstruction";
 import { BpfUpgradableLoaderInstruction } from "./BpfUpgradableLoaderMultisigInstruction";
 import { BPF_UPGRADABLE_LOADER } from "../bpf_upgradable_loader";
+import { AnchorAccounts } from "./anchor";
 
 export const UNRECOGNIZED_INSTRUCTION = "unrecognizedInstruction";
 export enum MultisigInstructionProgram {
@@ -26,22 +27,54 @@ export enum MultisigInstructionProgram {
   UnrecognizedProgram,
 }
 
+export function getProgramName(program: MultisigInstructionProgram) {
+  switch (program) {
+    case MultisigInstructionProgram.PythOracle:
+      return "Pyth Oracle";
+    case MultisigInstructionProgram.WormholeBridge:
+      return "Wormhole";
+    case MultisigInstructionProgram.MessageBuffer:
+      return "Message Buffer";
+    case MultisigInstructionProgram.SystemProgram:
+      return "System Program";
+    case MultisigInstructionProgram.BpfUpgradableLoader:
+      return "BPF Upgradable Loader";
+    case MultisigInstructionProgram.UnrecognizedProgram:
+      return "Unknown";
+  }
+}
+
 export interface MultisigInstruction {
   readonly program: MultisigInstructionProgram;
+  readonly name: string;
+  readonly args: { [key: string]: any };
+  readonly accounts: AnchorAccounts;
 }
 
 export class UnrecognizedProgram implements MultisigInstruction {
   readonly program = MultisigInstructionProgram.UnrecognizedProgram;
-  readonly instruction: TransactionInstruction;
+  readonly name: string;
+  readonly args: { [key: string]: any };
+  readonly accounts: AnchorAccounts;
 
-  constructor(instruction: TransactionInstruction) {
-    this.instruction = instruction;
+  constructor(
+    name: string,
+    args: { [key: string]: any },
+    accounts: AnchorAccounts
+  ) {
+    this.name = name;
+    this.args = args;
+    this.accounts = accounts;
   }
 
   static fromTransactionInstruction(
     instruction: TransactionInstruction
   ): UnrecognizedProgram {
-    return new UnrecognizedProgram(instruction);
+    return new UnrecognizedProgram(
+      UNRECOGNIZED_INSTRUCTION,
+      { data: instruction.data },
+      { named: {}, remaining: instruction.keys }
+    );
   }
 }
 export class MultisigParser {

+ 76 - 164
governance/xc_admin/packages/xc_admin_frontend/components/InstructionViews/WormholeInstructionView.tsx

@@ -1,22 +1,18 @@
 import {
   AptosAuthorizeUpgradeContract,
   AuthorizeGovernanceDataSourceTransfer,
-  BpfUpgradableLoaderInstruction,
   CosmosUpgradeContract,
   EvmSetWormholeAddress,
   EvmUpgradeContract,
   ExecutePostedVaa,
-  MessageBufferMultisigInstruction,
   MultisigParser,
   PythGovernanceAction,
-  PythMultisigInstruction,
   RequestGovernanceDataSourceTransfer,
   SetDataSources,
   SetFee,
   SetValidPeriod,
-  SystemProgramMultisigInstruction,
-  UnrecognizedProgram,
   WormholeMultisigInstruction,
+  getProgramName,
 } from 'xc_admin_common'
 import { AccountMeta, PublicKey } from '@solana/web3.js'
 import CopyPubkey from '../common/CopyPubkey'
@@ -85,133 +81,96 @@ export const WormholeInstructionView = ({
             <>
               <div key={`${index}_program`} className="flex justify-between">
                 <div>Program</div>
-                <div>
-                  {parsedInstruction instanceof PythMultisigInstruction
-                    ? 'Pyth Oracle'
-                    : parsedInstruction instanceof WormholeMultisigInstruction
-                    ? 'Wormhole'
-                    : parsedInstruction instanceof
-                      MessageBufferMultisigInstruction
-                    ? 'Message Buffer'
-                    : parsedInstruction instanceof
-                      SystemProgramMultisigInstruction
-                    ? 'System Program'
-                    : parsedInstruction instanceof
-                      BpfUpgradableLoaderInstruction
-                    ? 'BPF Upgradable Loader'
-                    : 'Unknown'}
-                </div>
+                <div>{getProgramName(parsedInstruction.program)}</div>
               </div>
               <div
                 key={`${index}_instructionName`}
                 className="flex justify-between"
               >
                 <div>Instruction Name</div>
-                <div>
-                  {parsedInstruction instanceof PythMultisigInstruction ||
-                  parsedInstruction instanceof WormholeMultisigInstruction ||
-                  parsedInstruction instanceof
-                    MessageBufferMultisigInstruction ||
-                  parsedInstruction instanceof
-                    SystemProgramMultisigInstruction ||
-                  parsedInstruction instanceof BpfUpgradableLoaderInstruction
-                    ? parsedInstruction.name
-                    : 'Unknown'}
-                </div>
+                <div>{parsedInstruction.name}</div>
               </div>
               <div
                 key={`${index}_arguments`}
                 className="grid grid-cols-4 justify-between"
               >
                 <div>Arguments</div>
-                {parsedInstruction instanceof PythMultisigInstruction ||
-                parsedInstruction instanceof WormholeMultisigInstruction ||
-                parsedInstruction instanceof MessageBufferMultisigInstruction ||
-                parsedInstruction instanceof SystemProgramMultisigInstruction ||
-                parsedInstruction instanceof BpfUpgradableLoaderInstruction ? (
-                  Object.keys(parsedInstruction.args).length > 0 ? (
-                    <div className="col-span-4 mt-2 bg-[#444157] p-4 lg:col-span-3 lg:mt-0">
-                      <div className="base16 flex justify-between pt-2 pb-6 font-semibold opacity-60">
-                        <div>Key</div>
-                        <div>Value</div>
-                      </div>
-                      {Object.keys(parsedInstruction.args).map((key, index) => (
-                        <>
-                          <div
-                            key={index}
-                            className="flex justify-between border-t border-beige-300 py-3"
-                          >
-                            {key === 'lamports' &&
-                            typeof parsedInstruction.args[key] === 'bigint' ? (
-                              <>
-                                <div>{'◎'}</div>
-                                <div>
-                                  {lamportsToSol(parsedInstruction.args[key])}
-                                </div>
-                              </>
-                            ) : (
-                              <>
-                                <div>{key}</div>
-                                {parsedInstruction.args[key] instanceof
-                                PublicKey ? (
-                                  <CopyPubkey
-                                    pubkey={parsedInstruction.args[
-                                      key
-                                    ].toBase58()}
-                                  />
-                                ) : typeof instruction.args[key] === 'string' &&
-                                  isPubkey(instruction.args[key]) ? (
-                                  <CopyPubkey
-                                    pubkey={parsedInstruction.args[key]}
-                                  />
-                                ) : (
-                                  <div className="max-w-sm break-all">
-                                    {typeof parsedInstruction.args[key] ===
-                                    'string'
-                                      ? parsedInstruction.args[key]
-                                      : parsedInstruction.args[key] instanceof
-                                        Uint8Array
-                                      ? parsedInstruction.args[key].toString(
-                                          'hex'
-                                        )
-                                      : typeof parsedInstruction.args[key] ===
-                                        'bigint'
-                                      ? parsedInstruction.args[key].toString()
-                                      : JSON.stringify(
-                                          parsedInstruction.args[key]
-                                        )}
-                                  </div>
-                                )}
-                              </>
-                            )}
-                          </div>
-                          {key === 'pub' &&
-                          parsedInstruction.args[key].toBase58() in
-                            publisherKeyToNameMappingCluster ? (
-                            <ParsedAccountPubkeyRow
-                              key={`${index}_${parsedInstruction.args[
-                                key
-                              ].toBase58()}`}
-                              mapping={publisherKeyToNameMappingCluster}
-                              title="publisher"
-                              pubkey={parsedInstruction.args[key].toBase58()}
-                            />
-                          ) : null}
-                        </>
-                      ))}
+                {Object.keys(parsedInstruction.args).length > 0 ? (
+                  <div className="col-span-4 mt-2 bg-[#444157] p-4 lg:col-span-3 lg:mt-0">
+                    <div className="base16 flex justify-between pt-2 pb-6 font-semibold opacity-60">
+                      <div>Key</div>
+                      <div>Value</div>
                     </div>
-                  ) : (
-                    <div className="col-span-3 text-right">No arguments</div>
-                  )
+                    {Object.keys(parsedInstruction.args).map((key, index) => (
+                      <>
+                        <div
+                          key={index}
+                          className="flex justify-between border-t border-beige-300 py-3"
+                        >
+                          {key === 'lamports' &&
+                          typeof parsedInstruction.args[key] === 'bigint' ? (
+                            <>
+                              <div>{'◎'}</div>
+                              <div>
+                                {lamportsToSol(parsedInstruction.args[key])}
+                              </div>
+                            </>
+                          ) : (
+                            <>
+                              <div>{key}</div>
+                              {parsedInstruction.args[key] instanceof
+                              PublicKey ? (
+                                <CopyPubkey
+                                  pubkey={parsedInstruction.args[
+                                    key
+                                  ].toBase58()}
+                                />
+                              ) : typeof instruction.args[key] === 'string' &&
+                                isPubkey(instruction.args[key]) ? (
+                                <CopyPubkey
+                                  pubkey={parsedInstruction.args[key]}
+                                />
+                              ) : (
+                                <div className="max-w-sm break-all">
+                                  {typeof parsedInstruction.args[key] ===
+                                  'string'
+                                    ? parsedInstruction.args[key]
+                                    : parsedInstruction.args[key] instanceof
+                                      Uint8Array
+                                    ? parsedInstruction.args[key].toString(
+                                        'hex'
+                                      )
+                                    : typeof parsedInstruction.args[key] ===
+                                      'bigint'
+                                    ? parsedInstruction.args[key].toString()
+                                    : JSON.stringify(
+                                        parsedInstruction.args[key]
+                                      )}
+                                </div>
+                              )}
+                            </>
+                          )}
+                        </div>
+                        {key === 'pub' &&
+                        parsedInstruction.args[key].toBase58() in
+                          publisherKeyToNameMappingCluster ? (
+                          <ParsedAccountPubkeyRow
+                            key={`${index}_${parsedInstruction.args[
+                              key
+                            ].toBase58()}`}
+                            mapping={publisherKeyToNameMappingCluster}
+                            title="publisher"
+                            pubkey={parsedInstruction.args[key].toBase58()}
+                          />
+                        ) : null}
+                      </>
+                    ))}
+                  </div>
                 ) : (
-                  <div className="col-span-3 text-right">Unknown</div>
+                  <div className="col-span-3 text-right">No arguments</div>
                 )}
               </div>
-              {parsedInstruction instanceof PythMultisigInstruction ||
-              parsedInstruction instanceof WormholeMultisigInstruction ||
-              parsedInstruction instanceof MessageBufferMultisigInstruction ||
-              parsedInstruction instanceof SystemProgramMultisigInstruction ||
-              parsedInstruction instanceof BpfUpgradableLoaderInstruction ? (
+              {
                 <div
                   key={`${index}_accounts`}
                   className="grid grid-cols-4 justify-between"
@@ -311,54 +270,7 @@ export const WormholeInstructionView = ({
                     <div>No accounts</div>
                   )}
                 </div>
-              ) : parsedInstruction instanceof UnrecognizedProgram ? (
-                <>
-                  <div
-                    key={`${index}_programId`}
-                    className="flex justify-between"
-                  >
-                    <div>Program ID</div>
-                    <div>
-                      {parsedInstruction.instruction.programId.toBase58()}
-                    </div>
-                  </div>
-                  <div key={`${index}_data`} className="flex justify-between">
-                    <div>Data</div>
-                    <div>
-                      {parsedInstruction.instruction.data.length > 0
-                        ? parsedInstruction.instruction.data.toString('hex')
-                        : 'No data'}
-                    </div>
-                  </div>
-                  <div
-                    key={`${index}_keys`}
-                    className="grid grid-cols-4 justify-between"
-                  >
-                    <div>Keys</div>
-                    <div className="col-span-4 mt-2 bg-darkGray4 p-4 lg:col-span-3 lg:mt-0">
-                      <div className="base16 flex justify-between pt-2 pb-6 font-semibold opacity-60">
-                        <div>Key #</div>
-                        <div>Pubkey</div>
-                      </div>
-                      {parsedInstruction.instruction.keys.map((key, index) => (
-                        <>
-                          <div
-                            key={index}
-                            className="flex justify-between border-t border-beige-300 py-3"
-                          >
-                            <div>Key {index + 1}</div>
-                            <div className="flex space-x-2">
-                              {key.isSigner ? <SignerTag /> : null}
-                              {key.isWritable ? <WritableTag /> : null}
-                              <CopyPubkey pubkey={key.pubkey.toBase58()} />
-                            </div>
-                          </div>
-                        </>
-                      ))}
-                    </div>
-                  </div>
-                </>
-              ) : null}
+              }
             </>
           )
         })}

+ 52 - 130
governance/xc_admin/packages/xc_admin_frontend/components/tabs/Proposals.tsx

@@ -12,11 +12,9 @@ import {
   MultisigParser,
   PythMultisigInstruction,
   MessageBufferMultisigInstruction,
-  UnrecognizedProgram,
   WormholeMultisigInstruction,
   getManyProposalsInstructions,
-  SystemProgramMultisigInstruction,
-  BpfUpgradableLoaderInstruction,
+  getProgramName,
 } from 'xc_admin_common'
 import { ClusterContext } from '../../contexts/ClusterContext'
 import { useMultisigContext } from '../../contexts/MultisigContext'
@@ -249,11 +247,7 @@ const Proposal = ({
   const multisigCluster = getMultisigCluster(contextCluster)
   const targetClusters: (PythCluster | 'unknown')[] = []
   instructions.map((ix) => {
-    if (
-      ix instanceof PythMultisigInstruction ||
-      ix instanceof SystemProgramMultisigInstruction ||
-      ix instanceof BpfUpgradableLoaderInstruction
-    ) {
+    if (!(ix instanceof WormholeMultisigInstruction)) {
       targetClusters.push(multisigCluster)
     } else if (
       ix instanceof WormholeMultisigInstruction &&
@@ -549,22 +543,9 @@ const Proposal = ({
               className="flex justify-between"
             >
               <div>Program</div>
-              <div>
-                {instruction instanceof PythMultisigInstruction
-                  ? 'Pyth Oracle'
-                  : instruction instanceof WormholeMultisigInstruction
-                  ? 'Wormhole'
-                  : instruction instanceof SystemProgramMultisigInstruction
-                  ? 'System Program'
-                  : instruction instanceof BpfUpgradableLoaderInstruction
-                  ? 'BPF Upgradable Loader'
-                  : 'Unknown'}
-              </div>
+              <div>{getProgramName(instruction.program)}</div>
             </div>
-            {instruction instanceof PythMultisigInstruction ||
-            instruction instanceof WormholeMultisigInstruction ||
-            instruction instanceof BpfUpgradableLoaderInstruction ||
-            instruction instanceof SystemProgramMultisigInstruction ? (
+            {
               <div
                 key={`${index}_instructionName`}
                 className="flex justify-between"
@@ -572,7 +553,7 @@ const Proposal = ({
                 <div>Instruction Name</div>
                 <div>{instruction.name}</div>
               </div>
-            ) : null}
+            }
             {instruction instanceof WormholeMultisigInstruction &&
             instruction.governanceAction ? (
               <>
@@ -585,69 +566,64 @@ const Proposal = ({
                 </div>
               </>
             ) : null}
-            {instruction instanceof WormholeMultisigInstruction ||
-            instruction instanceof UnrecognizedProgram ? null : (
+            {instruction instanceof WormholeMultisigInstruction ? null : (
               <div
                 key={`${index}_arguments`}
                 className="grid grid-cols-4 justify-between"
               >
                 <div>Arguments</div>
-                {instruction instanceof PythMultisigInstruction ||
-                instruction instanceof SystemProgramMultisigInstruction ||
-                instruction instanceof BpfUpgradableLoaderInstruction ? (
-                  Object.keys(instruction.args).length > 0 ? (
-                    <div className="col-span-4 mt-2 bg-darkGray2 p-4 lg:col-span-3 lg:mt-0">
-                      <div className="base16 flex justify-between pt-2 pb-6 font-semibold opacity-60">
-                        <div>Key</div>
-                        <div>Value</div>
-                      </div>
-                      {Object.keys(instruction.args).map((key, index) => (
-                        <Fragment key={index}>
-                          <div className="flex justify-between border-t border-beige-300 py-3">
-                            <div>{key}</div>
-                            {instruction.args[key] instanceof PublicKey ? (
-                              <CopyPubkey
-                                pubkey={instruction.args[key].toBase58()}
-                              />
-                            ) : typeof instruction.args[key] === 'string' &&
-                              isPubkey(instruction.args[key]) ? (
-                              <CopyPubkey pubkey={instruction.args[key]} />
-                            ) : (
-                              <div className="max-w-sm break-all">
-                                {typeof instruction.args[key] === 'string'
-                                  ? instruction.args[key]
-                                  : instruction.args[key] instanceof Uint8Array
-                                  ? instruction.args[key].toString('hex')
-                                  : JSON.stringify(instruction.args[key])}
-                              </div>
-                            )}
-                          </div>
-                          {key === 'pub' &&
-                          instruction.args[key].toBase58() in
-                            publisherKeyToNameMappingCluster ? (
-                            <ParsedAccountPubkeyRow
-                              key={`${index}_${instruction.args[
-                                key
-                              ].toBase58()}`}
-                              mapping={publisherKeyToNameMappingCluster}
-                              title="publisher"
+                {Object.keys(instruction.args).length > 0 ? (
+                  <div className="col-span-4 mt-2 bg-darkGray2 p-4 lg:col-span-3 lg:mt-0">
+                    <div className="base16 flex justify-between pt-2 pb-6 font-semibold opacity-60">
+                      <div>Key</div>
+                      <div>Value</div>
+                    </div>
+                    {Object.keys(instruction.args).map((key, index) => (
+                      <Fragment key={index}>
+                        <div className="flex justify-between border-t border-beige-300 py-3">
+                          <div>{key}</div>
+                          {instruction.args[key] instanceof PublicKey ? (
+                            <CopyPubkey
                               pubkey={instruction.args[key].toBase58()}
                             />
-                          ) : null}
-                        </Fragment>
-                      ))}
-                    </div>
-                  ) : (
-                    <div className="col-span-3 text-right">No arguments</div>
-                  )
+                          ) : typeof instruction.args[key] === 'string' &&
+                            isPubkey(instruction.args[key]) ? (
+                            <CopyPubkey pubkey={instruction.args[key]} />
+                          ) : (
+                            <div className="max-w-sm break-all">
+                              {typeof instruction.args[key] === 'string'
+                                ? instruction.args[key]
+                                : instruction.args[key] instanceof Uint8Array
+                                ? instruction.args[key].toString('hex')
+                                : JSON.stringify(instruction.args[key])}
+                            </div>
+                          )}
+                        </div>
+                        {key === 'pub' &&
+                        instruction.args[key].toBase58() in
+                          publisherKeyToNameMappingCluster ? (
+                          <ParsedAccountPubkeyRow
+                            key={`${index}_${instruction.args[key].toBase58()}`}
+                            mapping={publisherKeyToNameMappingCluster}
+                            title="publisher"
+                            pubkey={instruction.args[key].toBase58()}
+                          />
+                        ) : null}
+                      </Fragment>
+                    ))}
+                  </div>
                 ) : (
-                  <div className="col-span-3 text-right">Unknown</div>
+                  <div className="col-span-3 text-right">No arguments</div>
                 )}
               </div>
             )}
-            {instruction instanceof PythMultisigInstruction ||
-            instruction instanceof SystemProgramMultisigInstruction ||
-            instruction instanceof BpfUpgradableLoaderInstruction ? (
+            {instruction instanceof WormholeMultisigInstruction && (
+              <WormholeInstructionView
+                cluster={cluster}
+                instruction={instruction}
+              />
+            )}
+            {!(instruction instanceof WormholeMultisigInstruction) ? (
               <div
                 key={`${index}_accounts`}
                 className="grid grid-cols-4 justify-between"
@@ -716,61 +692,7 @@ const Proposal = ({
                   <div>No arguments</div>
                 )}
               </div>
-            ) : instruction instanceof UnrecognizedProgram ? (
-              <>
-                <div
-                  key={`${index}_programId`}
-                  className="flex justify-between"
-                >
-                  <div>Program ID</div>
-                  <CopyPubkey
-                    pubkey={instruction.instruction.programId.toBase58()}
-                  />
-                </div>
-                <div key={`${index}_data`} className="flex justify-between">
-                  <div>Data</div>
-                  <div className="max-w-sm break-all">
-                    {instruction.instruction.data.length > 0
-                      ? instruction.instruction.data.toString('hex')
-                      : 'No data'}
-                  </div>
-                </div>
-                <div
-                  key={`${index}_keys`}
-                  className="grid grid-cols-4 justify-between"
-                >
-                  <div>Keys</div>
-                  <div className="col-span-4 mt-2 bg-darkGray2 p-4 lg:col-span-3 lg:mt-0">
-                    <div className="base16 flex justify-between pt-2 pb-6 font-semibold opacity-60">
-                      <div>Key #</div>
-                      <div>Pubkey</div>
-                    </div>
-                    {instruction.instruction.keys.map((key, index) => (
-                      <>
-                        <div
-                          key={index}
-                          className="flex justify-between border-t border-beige-300 py-3"
-                        >
-                          <div>Key {index + 1}</div>
-                          <div className="flex space-x-2">
-                            {key.isSigner ? <SignerTag /> : null}
-                            {key.isWritable ? <WritableTag /> : null}
-                            <CopyPubkey pubkey={key.pubkey.toBase58()} />
-                          </div>
-                        </div>
-                      </>
-                    ))}
-                  </div>
-                </div>
-              </>
             ) : null}
-            {instruction instanceof WormholeMultisigInstruction && (
-              <WormholeInstructionView
-                cluster={cluster}
-                instruction={instruction}
-              />
-            )}
-
             {index !== instructions.length - 1 ? (
               <hr className="border-gray-700" />
             ) : null}