From e47b178d29cd5b4d5ea75f4d613ff81b32f5c451 Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Tue, 7 Apr 2020 01:27:54 +0800 Subject: [PATCH] Transaction modal fixes --- explorer/src/components/TransactionModal.tsx | 139 +++++++++++++------ explorer/src/providers/blocks.tsx | 54 ++++--- 2 files changed, 130 insertions(+), 63 deletions(-) diff --git a/explorer/src/components/TransactionModal.tsx b/explorer/src/components/TransactionModal.tsx index 1d4b77000a..45fcfa7756 100644 --- a/explorer/src/components/TransactionModal.tsx +++ b/explorer/src/components/TransactionModal.tsx @@ -5,8 +5,13 @@ import { ActionType, Selected } from "../providers/transactions"; +import { displayAddress } from "../utils"; import { useBlocks } from "../providers/blocks"; -import { LAMPORTS_PER_SOL } from "@solana/web3.js"; +import { + LAMPORTS_PER_SOL, + TransferParams, + CreateAccountParams +} from "@solana/web3.js"; function TransactionModal() { const { selected } = useTransactions(); @@ -45,24 +50,34 @@ function TransactionModal() { function TransactionDetails({ selected }: { selected: Selected }) { const { blocks } = useBlocks(); const block = blocks[selected.slot]; - if (!block) - return {"Transaction block not found"}; + + const renderError = (content: React.ReactNode) => { + return ( +
+ {content} +
+ ); + }; + + if (!block) return renderError("Transaction block not found"); if (!block.transactions) { - return ( - + return renderError( + <> Loading - + ); } const details = block.transactions[selected.signature]; - if (!details) - return {"Transaction not found"}; + if (!details) return renderError("Transaction not found"); - if (details.transfers.length === 0) - return {"No transfers"}; + const { transfers, creates } = details; + if (transfers.length === 0 && creates.length === 0) + return renderError( + "Details for this transaction's instructions are not yet supported" + ); let i = 0; return ( @@ -71,42 +86,15 @@ function TransactionDetails({ selected }: { selected: Selected }) { return (
{i > 1 ?
: null} -
-
-
-
-
-
From
-
-
- {transfer.fromPubkey.toBase58()} -
-
-
- -
-
-
-
To
-
-
- {transfer.toPubkey.toBase58()} -
-
-
- -
-
-
-
Amount (SOL)
-
-
- {`◎${(1.0 * transfer.lamports) / LAMPORTS_PER_SOL}`} -
-
-
-
-
+ +
+ ); + })} + {details.creates.map(create => { + return ( +
+ {i > 1 ?
: null} +
); })} @@ -114,4 +102,63 @@ function TransactionDetails({ selected }: { selected: Selected }) { ); } +function TransferDetails({ transfer }: { transfer: TransferParams }) { + return ( +
+
+ + {transfer.fromPubkey.toBase58()} + + + {transfer.toPubkey.toBase58()} + + + {`◎${(1.0 * transfer.lamports) / LAMPORTS_PER_SOL}`} + +
+
+ ); +} + +function CreateDetails({ create }: { create: CreateAccountParams }) { + return ( +
+
+ + {create.fromPubkey.toBase58()} + + + {create.newAccountPubkey.toBase58()} + + + {`◎${(1.0 * create.lamports) / LAMPORTS_PER_SOL}`} + + {create.space} + + {displayAddress(create.programId)} + +
+
+ ); +} + +function ListGroupItem({ + label, + children +}: { + label: string; + children: React.ReactNode; +}) { + return ( +
+
+
+
{label}
+
+
{children}
+
+
+ ); +} + export default TransactionModal; diff --git a/explorer/src/providers/blocks.tsx b/explorer/src/providers/blocks.tsx index 711b3d08cd..6b2ca70efa 100644 --- a/explorer/src/providers/blocks.tsx +++ b/explorer/src/providers/blocks.tsx @@ -5,7 +5,8 @@ import { Transaction, TransferParams, SystemProgram, - SystemInstruction + SystemInstruction, + CreateAccountParams } from "@solana/web3.js"; import { useCluster, ClusterStatus } from "./cluster"; import { useTransactions } from "./transactions"; @@ -19,6 +20,7 @@ export enum Status { export interface TransactionDetails { transaction: Transaction; transfers: Array; + creates: Array; } type Transactions = { [signature: string]: TransactionDetails }; @@ -152,6 +154,38 @@ export function BlocksProvider({ children }: BlocksProviderProps) { ); } +function decodeTransfers(tx: Transaction) { + const transferInstructions = tx.instructions + .filter(ix => ix.programId.equals(SystemProgram.programId)) + .filter(ix => SystemInstruction.decodeInstructionType(ix) === "Transfer"); + + let transfers: TransferParams[] = []; + transferInstructions.forEach(ix => { + try { + transfers.push(SystemInstruction.decodeTransfer(ix)); + } catch (err) { + console.error(ix, err); + } + }); + return transfers; +} + +function decodeCreates(tx: Transaction) { + const createInstructions = tx.instructions + .filter(ix => ix.programId.equals(SystemProgram.programId)) + .filter(ix => SystemInstruction.decodeInstructionType(ix) === "Create"); + + let creates: CreateAccountParams[] = []; + createInstructions.forEach(ix => { + try { + creates.push(SystemInstruction.decodeCreateAccount(ix)); + } catch (err) { + console.error(ix, err); + } + }); + return creates; +} + async function fetchBlock(dispatch: Dispatch, slot: number, url: string) { dispatch({ type: ActionType.Update, @@ -166,25 +200,11 @@ async function fetchBlock(dispatch: Dispatch, slot: number, url: string) { block.transactions.forEach(({ transaction }) => { const signature = transaction.signature; if (signature) { - const transferInstructions = transaction.instructions - .filter(ix => ix.programId.equals(SystemProgram.programId)) - .filter( - ix => SystemInstruction.decodeInstructionType(ix) === "Transfer" - ); - - let transfers: TransferParams[] = []; - transferInstructions.forEach(ix => { - try { - transfers.push(SystemInstruction.decodeTransfer(ix)); - } catch (err) { - console.log(ix, err); - } - }); - const sig = bs58.encode(signature); transactions[sig] = { transaction, - transfers + transfers: decodeTransfers(transaction), + creates: decodeCreates(transaction) }; } });