Refactor transaction provider

This commit is contained in:
Justin Starry 2020-04-29 11:00:06 +08:00 committed by Michael Vines
parent f3e677eaab
commit 6eff7f35c9
4 changed files with 93 additions and 96 deletions

View File

@ -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() {
</button>
</div>
<TransactionDetails selected={selected} />
<TransactionDetails signature={selected} />
</div>
</div>
</div>
@ -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 (

View File

@ -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({

View File

@ -97,9 +97,9 @@ export function DetailsProvider({ children }: DetailsProviderProps) {
if (status !== ClusterStatus.Connected) return;
const fetchSignatures = new Set<string>();
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[] = [];

View File

@ -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
});
}