Transaction modal fixes
This commit is contained in:
parent
0bda30e1f7
commit
e47b178d29
|
@ -5,8 +5,13 @@ import {
|
||||||
ActionType,
|
ActionType,
|
||||||
Selected
|
Selected
|
||||||
} from "../providers/transactions";
|
} from "../providers/transactions";
|
||||||
|
import { displayAddress } from "../utils";
|
||||||
import { useBlocks } from "../providers/blocks";
|
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() {
|
function TransactionModal() {
|
||||||
const { selected } = useTransactions();
|
const { selected } = useTransactions();
|
||||||
|
@ -45,24 +50,34 @@ function TransactionModal() {
|
||||||
function TransactionDetails({ selected }: { selected: Selected }) {
|
function TransactionDetails({ selected }: { selected: Selected }) {
|
||||||
const { blocks } = useBlocks();
|
const { blocks } = useBlocks();
|
||||||
const block = blocks[selected.slot];
|
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) {
|
if (!block.transactions) {
|
||||||
return (
|
return renderError(
|
||||||
<span className="text-info">
|
<>
|
||||||
<span className="spinner-grow spinner-grow-sm mr-2"></span>
|
<span className="spinner-grow spinner-grow-sm mr-2"></span>
|
||||||
Loading
|
Loading
|
||||||
</span>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const details = block.transactions[selected.signature];
|
const details = block.transactions[selected.signature];
|
||||||
if (!details)
|
if (!details) return renderError("Transaction not found");
|
||||||
return <span className="text-info">{"Transaction not found"}</span>;
|
|
||||||
|
|
||||||
if (details.transfers.length === 0)
|
const { transfers, creates } = details;
|
||||||
return <span className="text-info">{"No transfers"}</span>;
|
if (transfers.length === 0 && creates.length === 0)
|
||||||
|
return renderError(
|
||||||
|
"Details for this transaction's instructions are not yet supported"
|
||||||
|
);
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
return (
|
return (
|
||||||
|
@ -71,42 +86,15 @@ function TransactionDetails({ selected }: { selected: Selected }) {
|
||||||
return (
|
return (
|
||||||
<div key={++i}>
|
<div key={++i}>
|
||||||
{i > 1 ? <hr className="mb-4"></hr> : null}
|
{i > 1 ? <hr className="mb-4"></hr> : null}
|
||||||
<div className="card-body">
|
<TransferDetails transfer={transfer} />
|
||||||
<div className="list-group list-group-flush my-n3">
|
</div>
|
||||||
<div className="list-group-item">
|
);
|
||||||
<div className="row align-items-center">
|
})}
|
||||||
<div className="col">
|
{details.creates.map(create => {
|
||||||
<h5 className="mb-0">From</h5>
|
return (
|
||||||
</div>
|
<div key={++i}>
|
||||||
<div className="col-auto">
|
{i > 1 ? <hr className="mb-4"></hr> : null}
|
||||||
<code>{transfer.fromPubkey.toBase58()}</code>
|
<CreateDetails create={create} />
|
||||||
</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>
|
|
||||||
</div>
|
</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;
|
export default TransactionModal;
|
||||||
|
|
|
@ -5,7 +5,8 @@ import {
|
||||||
Transaction,
|
Transaction,
|
||||||
TransferParams,
|
TransferParams,
|
||||||
SystemProgram,
|
SystemProgram,
|
||||||
SystemInstruction
|
SystemInstruction,
|
||||||
|
CreateAccountParams
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import { useCluster, ClusterStatus } from "./cluster";
|
import { useCluster, ClusterStatus } from "./cluster";
|
||||||
import { useTransactions } from "./transactions";
|
import { useTransactions } from "./transactions";
|
||||||
|
@ -19,6 +20,7 @@ export enum Status {
|
||||||
export interface TransactionDetails {
|
export interface TransactionDetails {
|
||||||
transaction: Transaction;
|
transaction: Transaction;
|
||||||
transfers: Array<TransferParams>;
|
transfers: Array<TransferParams>;
|
||||||
|
creates: Array<CreateAccountParams>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Transactions = { [signature: string]: TransactionDetails };
|
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) {
|
async function fetchBlock(dispatch: Dispatch, slot: number, url: string) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionType.Update,
|
type: ActionType.Update,
|
||||||
|
@ -166,25 +200,11 @@ async function fetchBlock(dispatch: Dispatch, slot: number, url: string) {
|
||||||
block.transactions.forEach(({ transaction }) => {
|
block.transactions.forEach(({ transaction }) => {
|
||||||
const signature = transaction.signature;
|
const signature = transaction.signature;
|
||||||
if (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);
|
const sig = bs58.encode(signature);
|
||||||
transactions[sig] = {
|
transactions[sig] = {
|
||||||
transaction,
|
transaction,
|
||||||
transfers
|
transfers: decodeTransfers(transaction),
|
||||||
|
creates: decodeCreates(transaction)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue