diff --git a/explorer/src/components/TransactionModal.tsx b/explorer/src/components/TransactionModal.tsx
index fedef9f3db..bcc0a85c6d 100644
--- a/explorer/src/components/TransactionModal.tsx
+++ b/explorer/src/components/TransactionModal.tsx
@@ -3,15 +3,15 @@ import {
useDetails,
useTransactions,
useTransactionsDispatch,
- ActionType,
- Selected
+ ActionType
} from "../providers/transactions";
import { displayAddress, decodeCreate, decodeTransfer } from "../utils/tx";
import {
LAMPORTS_PER_SOL,
TransferParams,
CreateAccountParams,
- TransactionInstruction
+ TransactionInstruction,
+ TransactionSignature
} from "@solana/web3.js";
import Copyable from "./Copyable";
import Overlay from "./Overlay";
@@ -36,7 +36,7 @@ function TransactionModal() {
-
+
@@ -53,8 +53,12 @@ function TransactionModal() {
);
}
-function TransactionDetails({ selected }: { selected: Selected }) {
- const details = useDetails(selected.signature);
+function TransactionDetails({
+ signature
+}: {
+ signature: TransactionSignature;
+}) {
+ const details = useDetails(signature);
const renderError = (content: React.ReactNode) => {
return (
diff --git a/explorer/src/components/TransactionsCard.tsx b/explorer/src/components/TransactionsCard.tsx
index 010beca20b..b4ab4705a9 100644
--- a/explorer/src/components/TransactionsCard.tsx
+++ b/explorer/src/components/TransactionsCard.tsx
@@ -4,8 +4,8 @@ import {
useTransactionsDispatch,
checkTransactionStatus,
ActionType,
- Transaction,
- Status
+ TransactionState,
+ FetchStatus
} from "../providers/transactions";
import bs58 from "bs58";
import { assertUnreachable } from "../utils";
@@ -115,50 +115,50 @@ const renderHeader = () => {
};
const renderTransactionRow = (
- transaction: Transaction,
+ transaction: TransactionState,
dispatch: any,
url: string
) => {
+ const { fetchStatus, transactionStatus } = transaction;
+
let statusText;
let statusClass;
- switch (transaction.status) {
- case Status.CheckFailed:
+ switch (fetchStatus) {
+ case FetchStatus.FetchFailed:
statusClass = "dark";
statusText = "Cluster Error";
break;
- case Status.Checking:
+ case FetchStatus.Fetching:
statusClass = "info";
- statusText = "Checking";
+ statusText = "Fetching";
break;
- case Status.Success:
- statusClass = "success";
- statusText = "Success";
- break;
- case Status.Failure:
- statusClass = "danger";
- statusText = "Failed";
- break;
- case Status.Missing:
- statusClass = "warning";
- statusText = "Not Found";
+ case FetchStatus.Fetched: {
+ if (!transactionStatus) {
+ statusClass = "warning";
+ statusText = "Not Found";
+ } else if (transactionStatus.result.err) {
+ statusClass = "danger";
+ statusText = "Failed";
+ } else {
+ statusClass = "success";
+ statusText = "Success";
+ }
break;
+ }
default:
- return assertUnreachable(transaction.status);
+ return assertUnreachable(fetchStatus);
}
let slotText = "-";
- if (transaction.slot !== undefined) {
- slotText = `${transaction.slot}`;
- }
-
let confirmationsText = "-";
- if (transaction.confirmations !== undefined) {
- confirmationsText = `${transaction.confirmations}`;
+ if (transactionStatus) {
+ slotText = `${transactionStatus.slot}`;
+ confirmationsText = `${transactionStatus.confirmations}`;
}
const renderDetails = () => {
let onClick, icon;
- if (transaction.confirmations === "max") {
+ if (transactionStatus?.confirmations === "max") {
icon = "more-horizontal";
onClick = () =>
dispatch({
diff --git a/explorer/src/providers/transactions/details.tsx b/explorer/src/providers/transactions/details.tsx
index 574c0b05ee..45a8f4f6a6 100644
--- a/explorer/src/providers/transactions/details.tsx
+++ b/explorer/src/providers/transactions/details.tsx
@@ -97,9 +97,9 @@ export function DetailsProvider({ children }: DetailsProviderProps) {
if (status !== ClusterStatus.Connected) return;
const fetchSignatures = new Set();
- transactions.forEach(tx => {
- if (tx.slot && tx.confirmations === "max" && !state[tx.signature])
- fetchSignatures.add(tx.signature);
+ transactions.forEach(({ signature, transactionStatus }) => {
+ if (transactionStatus?.confirmations === "max" && !state[signature])
+ fetchSignatures.add(signature);
});
const fetchList: string[] = [];
diff --git a/explorer/src/providers/transactions/index.tsx b/explorer/src/providers/transactions/index.tsx
index 71d2294f40..929411eb0f 100644
--- a/explorer/src/providers/transactions/index.tsx
+++ b/explorer/src/providers/transactions/index.tsx
@@ -3,7 +3,8 @@ import {
TransactionSignature,
Connection,
SystemProgram,
- Account
+ Account,
+ SignatureResult
} from "@solana/web3.js";
import { findGetParameter, findPathSegment } from "../../utils/url";
import { useCluster, ClusterStatus } from "../cluster";
@@ -20,12 +21,10 @@ import {
ActionType as AccountsActionType
} from "../accounts";
-export enum Status {
- Checking,
- CheckFailed,
- Success,
- Failure,
- Missing
+export enum FetchStatus {
+ Fetching,
+ FetchFailed,
+ Fetched
}
enum Source {
@@ -35,24 +34,24 @@ enum Source {
export type Confirmations = number | "max";
-export interface Transaction {
- id: number;
- status: Status;
- source: Source;
- slot?: number;
- confirmations?: Confirmations;
- signature: TransactionSignature;
-}
-
-export interface Selected {
+export interface TransactionStatus {
slot: number;
- signature: TransactionSignature;
+ result: SignatureResult;
+ confirmations: Confirmations;
}
-type Transactions = { [signature: string]: Transaction };
+export interface TransactionState {
+ id: number;
+ source: Source;
+ fetchStatus: FetchStatus;
+ signature: TransactionSignature;
+ transactionStatus?: TransactionStatus;
+}
+
+type Transactions = { [signature: string]: TransactionState };
interface State {
idCounter: number;
- selected?: Selected;
+ selected?: TransactionSignature;
transactions: Transactions;
}
@@ -75,9 +74,8 @@ interface DeselectTransaction {
interface UpdateStatus {
type: ActionType.UpdateStatus;
signature: TransactionSignature;
- status: Status;
- slot?: number;
- confirmations?: Confirmations;
+ fetchStatus: FetchStatus;
+ transactionStatus?: TransactionStatus;
}
interface InputSignature {
@@ -90,6 +88,7 @@ type Action =
| InputSignature
| SelectTransaction
| DeselectTransaction;
+
type Dispatch = (action: Action) => void;
function reducer(state: State, action: Action): State {
@@ -99,37 +98,33 @@ function reducer(state: State, action: Action): State {
}
case ActionType.Select: {
const tx = state.transactions[action.signature];
- if (!tx.slot) return state;
- const selected = {
- slot: tx.slot,
- signature: tx.signature
- };
- return { ...state, selected };
+ return { ...state, selected: tx.signature };
}
case ActionType.InputSignature: {
if (!!state.transactions[action.signature]) return state;
- const idCounter = state.idCounter + 1;
+ const nextId = state.idCounter + 1;
const transactions = {
...state.transactions,
[action.signature]: {
- id: idCounter,
- status: Status.Checking,
+ id: nextId,
source: Source.Input,
- signature: action.signature
+ signature: action.signature,
+ fetchStatus: FetchStatus.Fetching
}
};
- return { ...state, transactions, idCounter };
+ return { ...state, transactions, idCounter: nextId };
}
case ActionType.UpdateStatus: {
let transaction = state.transactions[action.signature];
if (transaction) {
transaction = {
...transaction,
- status: action.status,
- slot: action.slot,
- confirmations: action.confirmations
+ fetchStatus: action.fetchStatus
};
+ if (action.transactionStatus) {
+ transaction.transactionStatus = action.transactionStatus;
+ }
const transactions = {
...state.transactions,
[action.signature]: transaction
@@ -171,13 +166,14 @@ function initState(): State {
const transactions = signatures.reduce(
(transactions: Transactions, signature) => {
if (!!transactions[signature]) return transactions;
- idCounter++;
+ const nextId = idCounter + 1;
transactions[signature] = {
- id: idCounter,
+ id: nextId,
+ source: Source.Url,
signature,
- status: Status.Checking,
- source: Source.Url
+ fetchStatus: FetchStatus.Fetching
};
+ idCounter++;
return transactions;
},
{}
@@ -269,44 +265,41 @@ export async function checkTransactionStatus(
) {
dispatch({
type: ActionType.UpdateStatus,
- status: Status.Checking,
- signature
+ signature,
+ fetchStatus: FetchStatus.Fetching
});
- let status;
- let slot;
- let confirmations: Confirmations | undefined;
+ let fetchStatus;
+ let transactionStatus: TransactionStatus | undefined;
try {
const { value } = await new Connection(url).getSignatureStatus(signature, {
searchTransactionHistory: true
});
- if (value === null) {
- status = Status.Missing;
- } else {
- slot = value.slot;
+ if (value !== null) {
+ let confirmations: Confirmations;
if (typeof value.confirmations === "number") {
confirmations = value.confirmations;
} else {
confirmations = "max";
}
- if (value.err) {
- status = Status.Failure;
- } else {
- status = Status.Success;
- }
+ transactionStatus = {
+ slot: value.slot,
+ confirmations,
+ result: { err: value.err }
+ };
}
+ fetchStatus = FetchStatus.Fetched;
} catch (error) {
- console.error("Failed to check transaction status", error);
- status = Status.CheckFailed;
+ console.error("Failed to fetch transaction status", error);
+ fetchStatus = FetchStatus.FetchFailed;
}
dispatch({
type: ActionType.UpdateStatus,
- status,
- slot,
- confirmations,
- signature
+ signature,
+ fetchStatus,
+ transactionStatus
});
}