Refactor MultisigInstruction (#1098)
* Refactor unknown * Cleanup * Cleanup further
This commit is contained in:
parent
6cebfef1df
commit
5c0c252cee
|
@ -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 {
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
</>
|
||||
)
|
||||
})}
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue