Transaction modal fixes

This commit is contained in:
Justin Starry 2020-04-07 01:27:54 +08:00 committed by Michael Vines
parent 0bda30e1f7
commit e47b178d29
2 changed files with 130 additions and 63 deletions

View File

@ -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 <span className="text-info">{"Transaction block not found"}</span>;
const renderError = (content: React.ReactNode) => {
return (
<div className="card-body">
<span className="text-info">{content}</span>
</div>
);
};
if (!block) return renderError("Transaction block not found");
if (!block.transactions) {
return (
<span className="text-info">
return renderError(
<>
<span className="spinner-grow spinner-grow-sm mr-2"></span>
Loading
</span>
</>
);
}
const details = block.transactions[selected.signature];
if (!details)
return <span className="text-info">{"Transaction not found"}</span>;
if (!details) return renderError("Transaction not found");
if (details.transfers.length === 0)
return <span className="text-info">{"No transfers"}</span>;
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 (
<div key={++i}>
{i > 1 ? <hr className="mb-4"></hr> : null}
<div className="card-body">
<div className="list-group list-group-flush my-n3">
<div className="list-group-item">
<div className="row align-items-center">
<div className="col">
<h5 className="mb-0">From</h5>
</div>
<div className="col-auto">
<code>{transfer.fromPubkey.toBase58()}</code>
</div>
</div>
</div>
<div className="list-group-item">
<div className="row align-items-center">
<div className="col">
<h5 className="mb-0">To</h5>
</div>
<div className="col-auto">
<code>{transfer.toPubkey.toBase58()}</code>
</div>
</div>
</div>
<div className="list-group-item">
<div className="row align-items-center">
<div className="col">
<h5 className="mb-0">Amount (SOL)</h5>
</div>
<div className="col-auto">
{`${(1.0 * transfer.lamports) / LAMPORTS_PER_SOL}`}
</div>
</div>
</div>
</div>
</div>
<TransferDetails transfer={transfer} />
</div>
);
})}
{details.creates.map(create => {
return (
<div key={++i}>
{i > 1 ? <hr className="mb-4"></hr> : null}
<CreateDetails create={create} />
</div>
);
})}
@ -114,4 +102,63 @@ function TransactionDetails({ selected }: { selected: Selected }) {
);
}
function TransferDetails({ transfer }: { transfer: TransferParams }) {
return (
<div className="card-body">
<div className="list-group list-group-flush my-n3">
<ListGroupItem label="From">
<code>{transfer.fromPubkey.toBase58()}</code>
</ListGroupItem>
<ListGroupItem label="To">
<code>{transfer.toPubkey.toBase58()}</code>
</ListGroupItem>
<ListGroupItem label="Amount (SOL)">
{`${(1.0 * transfer.lamports) / LAMPORTS_PER_SOL}`}
</ListGroupItem>
</div>
</div>
);
}
function CreateDetails({ create }: { create: CreateAccountParams }) {
return (
<div className="card-body">
<div className="list-group list-group-flush my-n3">
<ListGroupItem label="From">
<code>{create.fromPubkey.toBase58()}</code>
</ListGroupItem>
<ListGroupItem label="New Account">
<code>{create.newAccountPubkey.toBase58()}</code>
</ListGroupItem>
<ListGroupItem label="Amount (SOL)">
{`${(1.0 * create.lamports) / LAMPORTS_PER_SOL}`}
</ListGroupItem>
<ListGroupItem label="Data (Bytes)">{create.space}</ListGroupItem>
<ListGroupItem label="Owner">
<code>{displayAddress(create.programId)}</code>
</ListGroupItem>
</div>
</div>
);
}
function ListGroupItem({
label,
children
}: {
label: string;
children: React.ReactNode;
}) {
return (
<div className="list-group-item">
<div className="row align-items-center">
<div className="col">
<h5 className="mb-0">{label}</h5>
</div>
<div className="col-auto">{children}</div>
</div>
</div>
);
}
export default TransactionModal;

View File

@ -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<TransferParams>;
creates: Array<CreateAccountParams>;
}
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)
};
}
});