From 13af01dcc405d740a5d8b2b0ca8b58997a607178 Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Fri, 8 May 2020 23:36:41 +0800 Subject: [PATCH] Refactor instruction details components --- .../src/components/TransactionDetails.tsx | 288 ++---------------- .../instruction/CreateDetailsCard.tsx | 98 ++++++ .../instruction/InstructionCard.tsx | 55 ++++ .../components/instruction/RawDetailsCard.tsx | 57 ++++ .../instruction/TransferDetailsCard.tsx | 83 +++++ explorer/src/utils/tx.ts | 32 -- 6 files changed, 313 insertions(+), 300 deletions(-) create mode 100644 explorer/src/components/instruction/CreateDetailsCard.tsx create mode 100644 explorer/src/components/instruction/InstructionCard.tsx create mode 100644 explorer/src/components/instruction/RawDetailsCard.tsx create mode 100644 explorer/src/components/instruction/TransferDetailsCard.tsx diff --git a/explorer/src/components/TransactionDetails.tsx b/explorer/src/components/TransactionDetails.tsx index 2dd55ec9bb..5087672da0 100644 --- a/explorer/src/components/TransactionDetails.tsx +++ b/explorer/src/components/TransactionDetails.tsx @@ -1,5 +1,4 @@ import React from "react"; -import bs58 from "bs58"; import { Source, useFetchTransactionStatus, @@ -10,19 +9,15 @@ import { } from "../providers/transactions"; import { fetchDetails } from "providers/transactions/details"; import { useCluster, useClusterModal } from "providers/cluster"; -import { - TransactionSignature, - TransactionInstruction, - TransferParams, - CreateAccountParams, - SystemProgram, - SignatureResult -} from "@solana/web3.js"; +import { TransactionSignature, SystemInstruction } from "@solana/web3.js"; import ClusterStatusButton from "components/ClusterStatusButton"; import { lamportsToSolString } from "utils"; -import { displayAddress, decodeCreate, decodeTransfer } from "utils/tx"; +import { displayAddress } from "utils/tx"; import Copyable from "./Copyable"; import { useHistory, useLocation } from "react-router-dom"; +import { TransferDetailsCard } from "./instruction/TransferDetailsCard"; +import { CreateDetailsCard } from "./instruction/CreateDetailsCard"; +import { RawDetailsCard } from "./instruction/RawDetailsCard"; type Props = { signature: TransactionSignature }; export default function TransactionDetails({ signature }: Props) { @@ -265,50 +260,6 @@ function AccountsCard({ signature }: Props) { ); } -function ixResult(result: SignatureResult, index: number) { - if (result.err) { - const err = result.err as any; - const ixError = err["InstructionError"]; - if (ixError && Array.isArray(ixError)) { - const [errorIndex, error] = ixError; - if (Number.isInteger(errorIndex) && errorIndex === index) { - return ["warning", `Error: ${JSON.stringify(error)}`]; - } - } - return ["dark"]; - } - return ["success"]; -} - -type InstructionProps = { - title: string; - children: React.ReactNode; - result: SignatureResult; - index: number; -}; - -function InstructionCard({ title, children, result, index }: InstructionProps) { - const [resultClass, errorString] = ixResult(result, index); - return ( -
-
-

- - #{index + 1} - - {title} -

-

- - {errorString} - -

-
- {children} -
- ); -} - function InstructionsSection({ signature }: Props) { const status = useTransactionStatus(signature); const details = useTransactionDetails(signature); @@ -325,39 +276,24 @@ function InstructionsSection({ signature }: Props) { const result = status.info.result; const instructionDetails = transaction.instructions.map((ix, index) => { - const transfer = decodeTransfer(ix); - if (transfer) { - return ( - - - - ); + const props = { ix, result, index }; + + let instructionType; + try { + instructionType = SystemInstruction.decodeInstructionType(ix); + } catch (err) { + console.error(err); + return ; } - const create = decodeCreate(ix); - if (create) { - return ( - - - - ); + switch (instructionType) { + case "Transfer": + return ; + case "Create": + return ; + default: + return ; } - - return ( - - - - ); }); return ( @@ -374,190 +310,6 @@ function InstructionsSection({ signature }: Props) { ); } -function TransferDetails({ - ix, - transfer -}: { - ix: TransactionInstruction; - transfer: TransferParams; -}) { - const from = transfer.fromPubkey.toBase58(); - const to = transfer.toPubkey.toBase58(); - const [fromMeta, toMeta] = ix.keys; - return ( - <> - - Program - - - {displayAddress(SystemProgram.programId)} - - - - - - -
From Address
- {!fromMeta.isWritable && ( - Readonly - )} - {fromMeta.isSigner && ( - Signer - )} - - - - {from} - - - - - - -
To Address
- {!toMeta.isWritable && ( - Readonly - )} - {toMeta.isSigner && ( - Signer - )} - - - - {to} - - - - - - Transfer Amount (SOL) - {lamportsToSolString(transfer.lamports)} - - - ); -} - -function CreateDetails({ - ix, - create -}: { - ix: TransactionInstruction; - create: CreateAccountParams; -}) { - const from = create.fromPubkey.toBase58(); - const newKey = create.newAccountPubkey.toBase58(); - const [fromMeta, newMeta] = ix.keys; - - return ( - <> - - Program - - - {displayAddress(SystemProgram.programId)} - - - - - - -
From Address
- {!fromMeta.isWritable && ( - Readonly - )} - {fromMeta.isSigner && ( - Signer - )} - - - - {from} - - - - - - -
New Address
- {!newMeta.isWritable && ( - Readonly - )} - {newMeta.isSigner && ( - Signer - )} - - - - {newKey} - - - - - - Transfer Amount (SOL) - {lamportsToSolString(create.lamports)} - - - - Allocated Space (Bytes) - {create.space} - - - - Assigned Owner - - - {displayAddress(create.programId)} - - - - - ); -} - -function RawDetails({ ix }: { ix: TransactionInstruction }) { - return ( - <> - - Program - - - {displayAddress(ix.programId)} - - - - - {ix.keys.map(({ pubkey, isSigner, isWritable }, keyIndex) => ( - - -
Account #{keyIndex + 1}
- {!isWritable && ( - Readonly - )} - {isSigner && ( - Signer - )} - - - - {pubkey.toBase58()} - - - - ))} - - - Raw Data (Base58) - - - {bs58.encode(ix.data)} - - - - - ); -} - function LoadingCard() { return (
diff --git a/explorer/src/components/instruction/CreateDetailsCard.tsx b/explorer/src/components/instruction/CreateDetailsCard.tsx new file mode 100644 index 0000000000..21dc57c7f3 --- /dev/null +++ b/explorer/src/components/instruction/CreateDetailsCard.tsx @@ -0,0 +1,98 @@ +import React from "react"; +import { + TransactionInstruction, + SystemProgram, + SignatureResult, + SystemInstruction +} from "@solana/web3.js"; +import { lamportsToSolString } from "utils"; +import { displayAddress } from "utils/tx"; +import { InstructionCard } from "./InstructionCard"; +import Copyable from "components/Copyable"; +import { RawDetailsCard } from "./RawDetailsCard"; + +export function CreateDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + const { ix, index, result } = props; + + let create; + try { + create = SystemInstruction.decodeCreateAccount(ix); + } catch (err) { + console.error(err); + return ; + } + + const from = create.fromPubkey.toBase58(); + const newKey = create.newAccountPubkey.toBase58(); + const [fromMeta, newMeta] = ix.keys; + + return ( + + + Program + + + {displayAddress(SystemProgram.programId)} + + + + + + +
From Address
+ {!fromMeta.isWritable && ( + Readonly + )} + {fromMeta.isSigner && ( + Signer + )} + + + + {from} + + + + + + +
New Address
+ {!newMeta.isWritable && ( + Readonly + )} + {newMeta.isSigner && ( + Signer + )} + + + + {newKey} + + + + + + Transfer Amount (SOL) + {lamportsToSolString(create.lamports)} + + + + Allocated Space (Bytes) + {create.space} + + + + Assigned Owner + + + {displayAddress(create.programId)} + + + +
+ ); +} diff --git a/explorer/src/components/instruction/InstructionCard.tsx b/explorer/src/components/instruction/InstructionCard.tsx new file mode 100644 index 0000000000..3db9ef6e15 --- /dev/null +++ b/explorer/src/components/instruction/InstructionCard.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import { SignatureResult } from "@solana/web3.js"; + +type InstructionProps = { + title: string; + children: React.ReactNode; + result: SignatureResult; + index: number; +}; + +export function InstructionCard({ + title, + children, + result, + index +}: InstructionProps) { + const [resultClass, errorString] = ixResult(result, index); + return ( +
+
+

+ + #{index + 1} + + {title} +

+

+ + {errorString} + +

+
+
+ + {children} +
+
+
+ ); +} + +function ixResult(result: SignatureResult, index: number) { + if (result.err) { + const err = result.err as any; + const ixError = err["InstructionError"]; + if (ixError && Array.isArray(ixError)) { + const [errorIndex, error] = ixError; + if (Number.isInteger(errorIndex) && errorIndex === index) { + return ["warning", `Error: ${JSON.stringify(error)}`]; + } + } + return ["dark"]; + } + return ["success"]; +} diff --git a/explorer/src/components/instruction/RawDetailsCard.tsx b/explorer/src/components/instruction/RawDetailsCard.tsx new file mode 100644 index 0000000000..f5c13de623 --- /dev/null +++ b/explorer/src/components/instruction/RawDetailsCard.tsx @@ -0,0 +1,57 @@ +import React from "react"; +import bs58 from "bs58"; +import { TransactionInstruction, SignatureResult } from "@solana/web3.js"; +import { displayAddress } from "utils/tx"; +import { InstructionCard } from "./InstructionCard"; +import Copyable from "components/Copyable"; + +export function RawDetailsCard({ + ix, + index, + result +}: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + return ( + + + Program + + + {displayAddress(ix.programId)} + + + + + {ix.keys.map(({ pubkey, isSigner, isWritable }, keyIndex) => ( + + +
Account #{keyIndex + 1}
+ {!isWritable && ( + Readonly + )} + {isSigner && ( + Signer + )} + + + + {pubkey.toBase58()} + + + + ))} + + + Raw Data (Base58) + + + {bs58.encode(ix.data)} + + + +
+ ); +} diff --git a/explorer/src/components/instruction/TransferDetailsCard.tsx b/explorer/src/components/instruction/TransferDetailsCard.tsx new file mode 100644 index 0000000000..160e06d098 --- /dev/null +++ b/explorer/src/components/instruction/TransferDetailsCard.tsx @@ -0,0 +1,83 @@ +import React from "react"; +import { + TransactionInstruction, + SystemProgram, + SignatureResult, + SystemInstruction +} from "@solana/web3.js"; +import { lamportsToSolString } from "utils"; +import { displayAddress } from "utils/tx"; +import { InstructionCard } from "./InstructionCard"; +import Copyable from "components/Copyable"; +import { RawDetailsCard } from "./RawDetailsCard"; + +export function TransferDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + const { ix, index, result } = props; + + let transfer; + try { + transfer = SystemInstruction.decodeTransfer(ix); + } catch (err) { + console.error(err); + return ; + } + + const from = transfer.fromPubkey.toBase58(); + const to = transfer.toPubkey.toBase58(); + const [fromMeta, toMeta] = ix.keys; + return ( + + + Program + + + {displayAddress(SystemProgram.programId)} + + + + + + +
From Address
+ {!fromMeta.isWritable && ( + Readonly + )} + {fromMeta.isSigner && ( + Signer + )} + + + + {from} + + + + + + +
To Address
+ {!toMeta.isWritable && ( + Readonly + )} + {toMeta.isSigner && ( + Signer + )} + + + + {to} + + + + + + Transfer Amount (SOL) + {lamportsToSolString(transfer.lamports)} + +
+ ); +} diff --git a/explorer/src/utils/tx.ts b/explorer/src/utils/tx.ts index 797a9d588b..7f00dbd688 100644 --- a/explorer/src/utils/tx.ts +++ b/explorer/src/utils/tx.ts @@ -4,10 +4,6 @@ import { StakeProgram, VOTE_PROGRAM_ID, BpfLoader, - TransferParams, - SystemInstruction, - CreateAccountParams, - TransactionInstruction, SYSVAR_CLOCK_PUBKEY, SYSVAR_RENT_PUBKEY, SYSVAR_REWARDS_PUBKEY, @@ -53,31 +49,3 @@ export function displayAddress(pubkey: PublicKey): string { address ); } - -export function decodeTransfer( - ix: TransactionInstruction -): TransferParams | null { - if (!ix.programId.equals(SystemProgram.programId)) return null; - - try { - if (SystemInstruction.decodeInstructionType(ix) !== "Transfer") return null; - return SystemInstruction.decodeTransfer(ix); - } catch (err) { - console.error(ix, err); - return null; - } -} - -export function decodeCreate( - ix: TransactionInstruction -): CreateAccountParams | null { - if (!ix.programId.equals(SystemProgram.programId)) return null; - - try { - if (SystemInstruction.decodeInstructionType(ix) !== "Create") return null; - return SystemInstruction.decodeCreateAccount(ix); - } catch (err) { - console.error(ix, err); - return null; - } -}