Explorer: Display CPI details for transaction (#13801)
* explorer: show inner instructions on token history * resolve warnings * show inner instructions on transaction details page * adjust contrast and add inner instructions row * show inner instructions after slot 46915769 * token history show inner instructions after 46915769 * restrict early slots only on mainnet * self nit naming * self nit: better name for constant * add signature-truncate class * resolve incoming raw transaction on transactions details
This commit is contained in:
@ -3,6 +3,7 @@ import {
|
|||||||
PublicKey,
|
PublicKey,
|
||||||
ConfirmedSignatureInfo,
|
ConfirmedSignatureInfo,
|
||||||
ParsedInstruction,
|
ParsedInstruction,
|
||||||
|
PartiallyDecodedInstruction,
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import { CacheEntry, FetchStatus } from "providers/cache";
|
import { CacheEntry, FetchStatus } from "providers/cache";
|
||||||
import {
|
import {
|
||||||
@ -40,6 +41,13 @@ import {
|
|||||||
isSerumInstruction,
|
isSerumInstruction,
|
||||||
parseSerumInstructionTitle,
|
parseSerumInstructionTitle,
|
||||||
} from "components/instruction/serum/types";
|
} from "components/instruction/serum/types";
|
||||||
|
import { INNER_INSTRUCTIONS_START_SLOT } from "pages/TransactionDetailsPage";
|
||||||
|
import { useCluster, Cluster } from "providers/cluster";
|
||||||
|
|
||||||
|
type InstructionType = {
|
||||||
|
name: string;
|
||||||
|
innerInstructions: (ParsedInstruction | PartiallyDecodedInstruction)[];
|
||||||
|
};
|
||||||
|
|
||||||
export function TokenHistoryCard({ pubkey }: { pubkey: PublicKey }) {
|
export function TokenHistoryCard({ pubkey }: { pubkey: PublicKey }) {
|
||||||
const address = pubkey.toBase58();
|
const address = pubkey.toBase58();
|
||||||
@ -263,6 +271,7 @@ const TokenTransactionRow = React.memo(
|
|||||||
details: CacheEntry<Details> | undefined;
|
details: CacheEntry<Details> | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
const fetchDetails = useFetchTransactionDetails();
|
const fetchDetails = useFetchTransactionDetails();
|
||||||
|
const { cluster } = useCluster();
|
||||||
|
|
||||||
// Fetch details on load
|
// Fetch details on load
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -309,58 +318,91 @@ const TokenTransactionRow = React.memo(
|
|||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|
||||||
const tokenInstructionNames = instructions
|
let tokenInstructionNames: InstructionType[] = [];
|
||||||
.map((ix, index): string | undefined => {
|
|
||||||
let transactionInstruction;
|
if (details?.data?.transaction) {
|
||||||
if (details?.data?.transaction?.transaction) {
|
const transaction = details.data.transaction;
|
||||||
transactionInstruction = intoTransactionInstruction(
|
|
||||||
details.data.transaction.transaction,
|
tokenInstructionNames = instructions
|
||||||
index
|
.map((ix, index): InstructionType | undefined => {
|
||||||
);
|
let name = "Unknown";
|
||||||
}
|
|
||||||
|
const innerInstructions: (
|
||||||
|
| ParsedInstruction
|
||||||
|
| PartiallyDecodedInstruction
|
||||||
|
)[] = [];
|
||||||
|
|
||||||
if ("parsed" in ix) {
|
|
||||||
if (ix.program === "spl-token") {
|
|
||||||
return instructionTypeName(ix, tx);
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
transactionInstruction &&
|
|
||||||
isSerumInstruction(transactionInstruction)
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
return parseSerumInstructionTitle(transactionInstruction);
|
|
||||||
} catch (error) {
|
|
||||||
reportError(error, { signature: tx.signature });
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
transactionInstruction &&
|
|
||||||
isTokenSwapInstruction(transactionInstruction)
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
return parseTokenSwapInstructionTitle(transactionInstruction);
|
|
||||||
} catch (error) {
|
|
||||||
reportError(error, { signature: tx.signature });
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (
|
if (
|
||||||
ix.accounts.findIndex((account) =>
|
transaction.meta?.innerInstructions &&
|
||||||
account.equals(TOKEN_PROGRAM_ID)
|
(cluster !== Cluster.MainnetBeta ||
|
||||||
) >= 0
|
transaction.slot >= INNER_INSTRUCTIONS_START_SLOT)
|
||||||
) {
|
) {
|
||||||
return "Unknown (Inner)";
|
transaction.meta.innerInstructions.forEach((ix) => {
|
||||||
|
if (ix.index === index) {
|
||||||
|
ix.instructions.forEach((inner) => {
|
||||||
|
innerInstructions.push(inner);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return undefined;
|
|
||||||
}
|
let transactionInstruction;
|
||||||
})
|
if (transaction?.transaction) {
|
||||||
.filter((name) => name !== undefined) as string[];
|
transactionInstruction = intoTransactionInstruction(
|
||||||
|
transaction.transaction,
|
||||||
|
ix
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("parsed" in ix) {
|
||||||
|
if (ix.program === "spl-token") {
|
||||||
|
name = instructionTypeName(ix, tx);
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
transactionInstruction &&
|
||||||
|
isSerumInstruction(transactionInstruction)
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
name = parseSerumInstructionTitle(transactionInstruction);
|
||||||
|
} catch (error) {
|
||||||
|
reportError(error, { signature: tx.signature });
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
transactionInstruction &&
|
||||||
|
isTokenSwapInstruction(transactionInstruction)
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
name = parseTokenSwapInstructionTitle(transactionInstruction);
|
||||||
|
} catch (error) {
|
||||||
|
reportError(error, { signature: tx.signature });
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
ix.accounts.findIndex((account) =>
|
||||||
|
account.equals(TOKEN_PROGRAM_ID)
|
||||||
|
) >= 0
|
||||||
|
) {
|
||||||
|
name = "Unknown (Inner)";
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: name,
|
||||||
|
innerInstructions: innerInstructions,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter((name) => name !== undefined) as InstructionType[];
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{tokenInstructionNames.map((typeName, index) => {
|
{tokenInstructionNames.map((instructionType, index) => {
|
||||||
return (
|
return (
|
||||||
<tr key={index}>
|
<tr key={index}>
|
||||||
<td className="w-1">
|
<td className="w-1">
|
||||||
@ -373,14 +415,16 @@ const TokenTransactionRow = React.memo(
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td className="forced-truncate">
|
||||||
<Address pubkey={mint} link truncate />
|
<Address pubkey={mint} link truncateUnknown />
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>{typeName}</td>
|
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<Signature signature={tx.signature} link />
|
<InstructionDetails instructionType={instructionType} tx={tx} />
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td className="forced-truncate">
|
||||||
|
<Signature signature={tx.signature} link truncate />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
@ -389,3 +433,48 @@ const TokenTransactionRow = React.memo(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function InstructionDetails({
|
||||||
|
instructionType,
|
||||||
|
tx,
|
||||||
|
}: {
|
||||||
|
instructionType: InstructionType;
|
||||||
|
tx: ConfirmedSignatureInfo;
|
||||||
|
}) {
|
||||||
|
const [expanded, setExpanded] = React.useState(false);
|
||||||
|
|
||||||
|
let instructionTypes = instructionType.innerInstructions
|
||||||
|
.map((ix) => {
|
||||||
|
if ("parsed" in ix && ix.program === "spl-token") {
|
||||||
|
return instructionTypeName(ix, tx);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
})
|
||||||
|
.filter((type) => type !== undefined);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className="tree">
|
||||||
|
{instructionTypes.length > 0 && (
|
||||||
|
<span
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setExpanded(!expanded);
|
||||||
|
}}
|
||||||
|
className={`c-pointer fe mr-2 ${
|
||||||
|
expanded ? "fe-minus-square" : "fe-plus-square"
|
||||||
|
}`}
|
||||||
|
></span>
|
||||||
|
)}
|
||||||
|
{instructionType.name}
|
||||||
|
</p>
|
||||||
|
{expanded && (
|
||||||
|
<ul className="tree">
|
||||||
|
{instructionTypes.map((type, index) => {
|
||||||
|
return <li key={index}>{type}</li>;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -12,9 +12,17 @@ type Props = {
|
|||||||
link?: boolean;
|
link?: boolean;
|
||||||
raw?: boolean;
|
raw?: boolean;
|
||||||
truncate?: boolean;
|
truncate?: boolean;
|
||||||
|
truncateUnknown?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Address({ pubkey, alignRight, link, raw, truncate }: Props) {
|
export function Address({
|
||||||
|
pubkey,
|
||||||
|
alignRight,
|
||||||
|
link,
|
||||||
|
raw,
|
||||||
|
truncate,
|
||||||
|
truncateUnknown,
|
||||||
|
}: Props) {
|
||||||
const [state, setState] = useState<CopyState>("copy");
|
const [state, setState] = useState<CopyState>("copy");
|
||||||
const address = pubkey.toBase58();
|
const address = pubkey.toBase58();
|
||||||
const { cluster } = useCluster();
|
const { cluster } = useCluster();
|
||||||
@ -33,6 +41,10 @@ export function Address({ pubkey, alignRight, link, raw, truncate }: Props) {
|
|||||||
<span className="fe fe-check-circle"></span>
|
<span className="fe fe-check-circle"></span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (truncateUnknown && address === displayAddress(address, cluster)) {
|
||||||
|
truncate = true;
|
||||||
|
}
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<>
|
<>
|
||||||
<span className="c-pointer font-size-tiny mr-2">{copyIcon}</span>
|
<span className="c-pointer font-size-tiny mr-2">{copyIcon}</span>
|
||||||
|
@ -8,9 +8,10 @@ type Props = {
|
|||||||
signature: TransactionSignature;
|
signature: TransactionSignature;
|
||||||
alignRight?: boolean;
|
alignRight?: boolean;
|
||||||
link?: boolean;
|
link?: boolean;
|
||||||
|
truncate?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Signature({ signature, alignRight, link }: Props) {
|
export function Signature({ signature, alignRight, link, truncate }: Props) {
|
||||||
const [state, setState] = useState<CopyState>("copy");
|
const [state, setState] = useState<CopyState>("copy");
|
||||||
|
|
||||||
const copyToClipboard = () => navigator.clipboard.writeText(signature);
|
const copyToClipboard = () => navigator.clipboard.writeText(signature);
|
||||||
@ -40,7 +41,10 @@ export function Signature({ signature, alignRight, link }: Props) {
|
|||||||
{copyButton}
|
{copyButton}
|
||||||
<span className="text-monospace">
|
<span className="text-monospace">
|
||||||
{link ? (
|
{link ? (
|
||||||
<Link className="" to={clusterPath(`/tx/${signature}`)}>
|
<Link
|
||||||
|
className={truncate ? "text-truncate signature-truncate" : ""}
|
||||||
|
to={clusterPath(`/tx/${signature}`)}
|
||||||
|
>
|
||||||
{signature}
|
{signature}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
|
@ -20,6 +20,8 @@ type InstructionProps = {
|
|||||||
index: number;
|
index: number;
|
||||||
ix: TransactionInstruction | ParsedInstruction;
|
ix: TransactionInstruction | ParsedInstruction;
|
||||||
defaultRaw?: boolean;
|
defaultRaw?: boolean;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function InstructionCard({
|
export function InstructionCard({
|
||||||
@ -29,6 +31,8 @@ export function InstructionCard({
|
|||||||
index,
|
index,
|
||||||
ix,
|
ix,
|
||||||
defaultRaw,
|
defaultRaw,
|
||||||
|
innerCards,
|
||||||
|
childIndex,
|
||||||
}: InstructionProps) {
|
}: InstructionProps) {
|
||||||
const [resultClass] = ixResult(result, index);
|
const [resultClass] = ixResult(result, index);
|
||||||
const [showRaw, setShowRaw] = React.useState(defaultRaw || false);
|
const [showRaw, setShowRaw] = React.useState(defaultRaw || false);
|
||||||
@ -55,6 +59,7 @@ export function InstructionCard({
|
|||||||
<h3 className="card-header-title mb-0 d-flex align-items-center">
|
<h3 className="card-header-title mb-0 d-flex align-items-center">
|
||||||
<span className={`badge badge-soft-${resultClass} mr-2`}>
|
<span className={`badge badge-soft-${resultClass} mr-2`}>
|
||||||
#{index + 1}
|
#{index + 1}
|
||||||
|
{childIndex !== undefined ? `.${childIndex + 1}` : ""}
|
||||||
</span>
|
</span>
|
||||||
{title}
|
{title}
|
||||||
</h3>
|
</h3>
|
||||||
@ -92,6 +97,14 @@ export function InstructionCard({
|
|||||||
) : (
|
) : (
|
||||||
children
|
children
|
||||||
)}
|
)}
|
||||||
|
{innerCards && innerCards.length > 0 && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={2}>
|
||||||
|
Inner Instructions
|
||||||
|
<div className="inner-cards">{innerCards}</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,14 +7,25 @@ export function MemoDetailsCard({
|
|||||||
ix,
|
ix,
|
||||||
index,
|
index,
|
||||||
result,
|
result,
|
||||||
|
innerCards,
|
||||||
|
childIndex,
|
||||||
}: {
|
}: {
|
||||||
ix: ParsedInstruction;
|
ix: ParsedInstruction;
|
||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const data = wrap(ix.parsed, 50);
|
const data = wrap(ix.parsed, 50);
|
||||||
return (
|
return (
|
||||||
<InstructionCard ix={ix} index={index} result={result} title="Memo">
|
<InstructionCard
|
||||||
|
ix={ix}
|
||||||
|
index={index}
|
||||||
|
result={result}
|
||||||
|
title="Memo"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Data (UTF-8)</td>
|
<td>Data (UTF-8)</td>
|
||||||
<td className="text-lg-right">
|
<td className="text-lg-right">
|
||||||
|
@ -29,8 +29,10 @@ export function SerumDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
signature: string;
|
signature: string;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, signature } = props;
|
const { ix, index, result, signature, innerCards, childIndex } = props;
|
||||||
|
|
||||||
const { url } = useCluster();
|
const { url } = useCluster();
|
||||||
|
|
||||||
@ -91,6 +93,8 @@ export function SerumDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title={`Serum: ${title || "Unknown"}`}
|
title={`Serum: ${title || "Unknown"}`}
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
defaultRaw
|
defaultRaw
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -10,11 +10,15 @@ export function TokenSwapDetailsCard({
|
|||||||
index,
|
index,
|
||||||
result,
|
result,
|
||||||
signature,
|
signature,
|
||||||
|
innerCards,
|
||||||
|
childIndex,
|
||||||
}: {
|
}: {
|
||||||
ix: TransactionInstruction;
|
ix: TransactionInstruction;
|
||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
signature: string;
|
signature: string;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { url } = useCluster();
|
const { url } = useCluster();
|
||||||
|
|
||||||
@ -34,6 +38,8 @@ export function TokenSwapDetailsCard({
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title={`Token Swap: ${title || "Unknown"}`}
|
title={`Token Swap: ${title || "Unknown"}`}
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
defaultRaw
|
defaultRaw
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -10,10 +10,14 @@ export function UnknownDetailsCard({
|
|||||||
ix,
|
ix,
|
||||||
index,
|
index,
|
||||||
result,
|
result,
|
||||||
|
innerCards,
|
||||||
|
childIndex,
|
||||||
}: {
|
}: {
|
||||||
ix: TransactionInstruction | ParsedInstruction;
|
ix: TransactionInstruction | ParsedInstruction;
|
||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -21,6 +25,8 @@ export function UnknownDetailsCard({
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Unknown"
|
title="Unknown"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
defaultRaw
|
defaultRaw
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -19,6 +19,8 @@ type DetailsProps = {
|
|||||||
ix: ParsedInstruction;
|
ix: ParsedInstruction;
|
||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function BpfLoaderDetailsCard(props: DetailsProps) {
|
export function BpfLoaderDetailsCard(props: DetailsProps) {
|
||||||
@ -50,10 +52,12 @@ type Props<T> = {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: T;
|
info: T;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function BpfLoaderWriteDetailsCard(props: Props<WriteInfo>) {
|
export function BpfLoaderWriteDetailsCard(props: Props<WriteInfo>) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
const bytes = wrap(info.bytes, 50);
|
const bytes = wrap(info.bytes, 50);
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -61,6 +65,8 @@ export function BpfLoaderWriteDetailsCard(props: Props<WriteInfo>) {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="BPF Loader 2: Write"
|
title="BPF Loader 2: Write"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
@ -94,7 +100,7 @@ export function BpfLoaderWriteDetailsCard(props: Props<WriteInfo>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function BpfLoaderFinalizeDetailsCard(props: Props<FinalizeInfo>) {
|
export function BpfLoaderFinalizeDetailsCard(props: Props<FinalizeInfo>) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -102,6 +108,8 @@ export function BpfLoaderFinalizeDetailsCard(props: Props<FinalizeInfo>) {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="BPF Loader 2: Finalize"
|
title="BPF Loader 2: Finalize"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -9,8 +9,10 @@ export function CancelOrderByClientIdDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: CancelOrderByClientId;
|
info: CancelOrderByClientId;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -18,6 +20,8 @@ export function CancelOrderByClientIdDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Serum: Cancel Order By Client Id"
|
title="Serum: Cancel Order By Client Id"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Market</td>
|
<td>Market</td>
|
||||||
|
@ -9,8 +9,10 @@ export function CancelOrderDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: CancelOrder;
|
info: CancelOrder;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -18,6 +20,8 @@ export function CancelOrderDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Serum: Cancel Order"
|
title="Serum: Cancel Order"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -9,8 +9,10 @@ export function ConsumeEventsDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: ConsumeEvents;
|
info: ConsumeEvents;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -18,6 +20,8 @@ export function ConsumeEventsDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Serum: Consume Events"
|
title="Serum: Consume Events"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -9,8 +9,10 @@ export function InitializeMarketDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: InitializeMarket;
|
info: InitializeMarket;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -18,6 +20,8 @@ export function InitializeMarketDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Serum: Initialize Market"
|
title="Serum: Initialize Market"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -9,8 +9,10 @@ export function MatchOrdersDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: MatchOrders;
|
info: MatchOrders;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -18,6 +20,8 @@ export function MatchOrdersDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Serum: Match Orders"
|
title="Serum: Match Orders"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -9,8 +9,10 @@ export function NewOrderDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: NewOrder;
|
info: NewOrder;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -18,6 +20,8 @@ export function NewOrderDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Serum: New Order"
|
title="Serum: New Order"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -9,8 +9,10 @@ export function SettleFundsDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: SettleFunds;
|
info: SettleFunds;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -18,6 +20,8 @@ export function SettleFundsDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Serum: Settle Funds"
|
title="Serum: Settle Funds"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -13,8 +13,10 @@ export function AuthorizeDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: AuthorizeInfo;
|
info: AuthorizeInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -22,6 +24,8 @@ export function AuthorizeDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Stake Authorize"
|
title="Stake Authorize"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -13,8 +13,10 @@ export function DeactivateDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: DeactivateInfo;
|
info: DeactivateInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -22,6 +24,8 @@ export function DeactivateDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Deactivate Stake"
|
title="Deactivate Stake"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -13,8 +13,10 @@ export function DelegateDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: DelegateInfo;
|
info: DelegateInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -22,6 +24,8 @@ export function DelegateDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Delegate Stake"
|
title="Delegate Stake"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -14,8 +14,10 @@ export function InitializeDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: InitializeInfo;
|
info: InitializeInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -23,6 +25,8 @@ export function InitializeDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Stake Initialize"
|
title="Stake Initialize"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -14,11 +14,20 @@ export function SplitDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: SplitInfo;
|
info: SplitInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard ix={ix} index={index} result={result} title="Split Stake">
|
<InstructionCard
|
||||||
|
ix={ix}
|
||||||
|
index={index}
|
||||||
|
result={result}
|
||||||
|
title="Split Stake"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
<td className="text-lg-right">
|
<td className="text-lg-right">
|
||||||
|
@ -29,6 +29,8 @@ type DetailsProps = {
|
|||||||
ix: ParsedInstruction;
|
ix: ParsedInstruction;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
index: number;
|
index: number;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function StakeDetailsCard(props: DetailsProps) {
|
export function StakeDetailsCard(props: DetailsProps) {
|
||||||
|
@ -14,8 +14,10 @@ export function WithdrawDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: WithdrawInfo;
|
info: WithdrawInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -23,6 +25,8 @@ export function WithdrawDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Withdraw Stake"
|
title="Withdraw Stake"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -13,8 +13,10 @@ export function AllocateDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: AllocateInfo;
|
info: AllocateInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -22,6 +24,8 @@ export function AllocateDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Allocate Account"
|
title="Allocate Account"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -14,8 +14,10 @@ export function AllocateWithSeedDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: AllocateWithSeedInfo;
|
info: AllocateWithSeedInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -23,6 +25,8 @@ export function AllocateWithSeedDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Allocate Account w/ Seed"
|
title="Allocate Account w/ Seed"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -13,8 +13,10 @@ export function AssignDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: AssignInfo;
|
info: AssignInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -22,6 +24,8 @@ export function AssignDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Assign Account"
|
title="Assign Account"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -14,8 +14,10 @@ export function AssignWithSeedDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: AssignWithSeedInfo;
|
info: AssignWithSeedInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -23,6 +25,8 @@ export function AssignWithSeedDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Assign Account w/ Seed"
|
title="Assign Account w/ Seed"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -14,8 +14,10 @@ export function CreateDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: CreateAccountInfo;
|
info: CreateAccountInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -23,6 +25,8 @@ export function CreateDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Create Account"
|
title="Create Account"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -15,8 +15,10 @@ export function CreateWithSeedDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: CreateAccountWithSeedInfo;
|
info: CreateAccountWithSeedInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -24,6 +26,8 @@ export function CreateWithSeedDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Create Account w/ Seed"
|
title="Create Account w/ Seed"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -13,8 +13,10 @@ export function NonceAdvanceDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: AdvanceNonceInfo;
|
info: AdvanceNonceInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -22,6 +24,8 @@ export function NonceAdvanceDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Advance Nonce"
|
title="Advance Nonce"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -13,8 +13,10 @@ export function NonceAuthorizeDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: AuthorizeNonceInfo;
|
info: AuthorizeNonceInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -22,6 +24,8 @@ export function NonceAuthorizeDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Authorize Nonce"
|
title="Authorize Nonce"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -13,8 +13,10 @@ export function NonceInitializeDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: InitializeNonceInfo;
|
info: InitializeNonceInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -22,6 +24,8 @@ export function NonceInitializeDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Initialize Nonce"
|
title="Initialize Nonce"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -14,8 +14,10 @@ export function NonceWithdrawDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: WithdrawNonceInfo;
|
info: WithdrawNonceInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard
|
<InstructionCard
|
||||||
@ -23,6 +25,8 @@ export function NonceWithdrawDetailsCard(props: {
|
|||||||
index={index}
|
index={index}
|
||||||
result={result}
|
result={result}
|
||||||
title="Withdraw Nonce"
|
title="Withdraw Nonce"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
>
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
|
@ -39,6 +39,8 @@ type DetailsProps = {
|
|||||||
ix: ParsedInstruction;
|
ix: ParsedInstruction;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
index: number;
|
index: number;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function SystemDetailsCard(props: DetailsProps) {
|
export function SystemDetailsCard(props: DetailsProps) {
|
||||||
|
@ -14,11 +14,20 @@ export function TransferDetailsCard(props: {
|
|||||||
index: number;
|
index: number;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
info: TransferInfo;
|
info: TransferInfo;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
}) {
|
}) {
|
||||||
const { ix, index, result, info } = props;
|
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstructionCard ix={ix} index={index} result={result} title="Transfer">
|
<InstructionCard
|
||||||
|
ix={ix}
|
||||||
|
index={index}
|
||||||
|
result={result}
|
||||||
|
title="Transfer"
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Program</td>
|
<td>Program</td>
|
||||||
<td className="text-lg-right">
|
<td className="text-lg-right">
|
||||||
|
@ -14,7 +14,7 @@ export const PROGRAM_IDS: string[] = [
|
|||||||
|
|
||||||
const INSTRUCTION_LOOKUP: { [key: number]: string } = {
|
const INSTRUCTION_LOOKUP: { [key: number]: string } = {
|
||||||
0: "Initialize Swap",
|
0: "Initialize Swap",
|
||||||
1: "Swap",
|
1: "Exchange",
|
||||||
2: "Deposit",
|
2: "Deposit",
|
||||||
3: "Withdraw",
|
3: "Withdraw",
|
||||||
};
|
};
|
||||||
|
@ -32,6 +32,8 @@ type DetailsProps = {
|
|||||||
ix: ParsedInstruction;
|
ix: ParsedInstruction;
|
||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
index: number;
|
index: number;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TokenDetailsCard(props: DetailsProps) {
|
export function TokenDetailsCard(props: DetailsProps) {
|
||||||
@ -56,6 +58,8 @@ type InfoProps = {
|
|||||||
result: SignatureResult;
|
result: SignatureResult;
|
||||||
index: number;
|
index: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
function TokenInstruction(props: InfoProps) {
|
function TokenInstruction(props: InfoProps) {
|
||||||
@ -195,6 +199,8 @@ function TokenInstruction(props: InfoProps) {
|
|||||||
index={props.index}
|
index={props.index}
|
||||||
result={props.result}
|
result={props.result}
|
||||||
title={props.title}
|
title={props.title}
|
||||||
|
innerCards={props.innerCards}
|
||||||
|
childIndex={props.childIndex}
|
||||||
>
|
>
|
||||||
{attributes}
|
{attributes}
|
||||||
</InstructionCard>
|
</InstructionCard>
|
||||||
|
@ -6,12 +6,19 @@ import {
|
|||||||
useTransactionDetails,
|
useTransactionDetails,
|
||||||
} from "providers/transactions";
|
} from "providers/transactions";
|
||||||
import { useFetchTransactionDetails } from "providers/transactions/details";
|
import { useFetchTransactionDetails } from "providers/transactions/details";
|
||||||
import { useCluster, ClusterStatus } from "providers/cluster";
|
import { useCluster, ClusterStatus, Cluster } from "providers/cluster";
|
||||||
import {
|
import {
|
||||||
TransactionSignature,
|
TransactionSignature,
|
||||||
SystemProgram,
|
SystemProgram,
|
||||||
SystemInstruction,
|
SystemInstruction,
|
||||||
|
ParsedInstruction,
|
||||||
|
PartiallyDecodedInstruction,
|
||||||
|
SignatureResult,
|
||||||
|
ParsedTransaction,
|
||||||
|
ParsedInnerInstruction,
|
||||||
|
Transaction,
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
|
import { PublicKey } from "@solana/web3.js";
|
||||||
import { lamportsToSolString } from "utils";
|
import { lamportsToSolString } from "utils";
|
||||||
import { UnknownDetailsCard } from "components/instruction/UnknownDetailsCard";
|
import { UnknownDetailsCard } from "components/instruction/UnknownDetailsCard";
|
||||||
import { SystemDetailsCard } from "components/instruction/system/SystemDetailsCard";
|
import { SystemDetailsCard } from "components/instruction/system/SystemDetailsCard";
|
||||||
@ -36,6 +43,7 @@ import { MemoDetailsCard } from "components/instruction/MemoDetailsCard";
|
|||||||
|
|
||||||
const AUTO_REFRESH_INTERVAL = 2000;
|
const AUTO_REFRESH_INTERVAL = 2000;
|
||||||
const ZERO_CONFIRMATION_BAILOUT = 5;
|
const ZERO_CONFIRMATION_BAILOUT = 5;
|
||||||
|
export const INNER_INSTRUCTIONS_START_SLOT = 46915769;
|
||||||
|
|
||||||
type SignatureProps = {
|
type SignatureProps = {
|
||||||
signature: TransactionSignature;
|
signature: TransactionSignature;
|
||||||
@ -194,7 +202,10 @@ function StatusCard({
|
|||||||
const blockhash = transaction?.message.recentBlockhash;
|
const blockhash = transaction?.message.recentBlockhash;
|
||||||
const isNonce = (() => {
|
const isNonce = (() => {
|
||||||
if (!transaction) return false;
|
if (!transaction) return false;
|
||||||
const ix = intoTransactionInstruction(transaction, 0);
|
const ix = intoTransactionInstruction(
|
||||||
|
transaction,
|
||||||
|
transaction.message.instructions[0]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
ix &&
|
ix &&
|
||||||
SystemProgram.programId.equals(ix.programId) &&
|
SystemProgram.programId.equals(ix.programId) &&
|
||||||
@ -399,6 +410,7 @@ function AccountsCard({
|
|||||||
function InstructionsSection({ signature }: SignatureProps) {
|
function InstructionsSection({ signature }: SignatureProps) {
|
||||||
const status = useTransactionStatus(signature);
|
const status = useTransactionStatus(signature);
|
||||||
const details = useTransactionDetails(signature);
|
const details = useTransactionDetails(signature);
|
||||||
|
const { cluster } = useCluster();
|
||||||
const fetchDetails = useFetchTransactionDetails();
|
const fetchDetails = useFetchTransactionDetails();
|
||||||
const refreshDetails = () => fetchDetails(signature);
|
const refreshDetails = () => fetchDetails(signature);
|
||||||
|
|
||||||
@ -407,95 +419,66 @@ function InstructionsSection({ signature }: SignatureProps) {
|
|||||||
const raw = details.data.raw?.transaction;
|
const raw = details.data.raw?.transaction;
|
||||||
|
|
||||||
const { transaction } = details.data.transaction;
|
const { transaction } = details.data.transaction;
|
||||||
|
const { meta } = details.data.transaction;
|
||||||
|
|
||||||
if (transaction.message.instructions.length === 0) {
|
if (transaction.message.instructions.length === 0) {
|
||||||
return <ErrorCard retry={refreshDetails} text="No instructions found" />;
|
return <ErrorCard retry={refreshDetails} text="No instructions found" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const innerInstructions: {
|
||||||
|
[index: number]: (ParsedInstruction | PartiallyDecodedInstruction)[];
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
if (
|
||||||
|
meta?.innerInstructions &&
|
||||||
|
(cluster !== Cluster.MainnetBeta ||
|
||||||
|
details.data.transaction.slot >= INNER_INSTRUCTIONS_START_SLOT)
|
||||||
|
) {
|
||||||
|
meta.innerInstructions.forEach((parsed: ParsedInnerInstruction) => {
|
||||||
|
if (!innerInstructions[parsed.index]) {
|
||||||
|
innerInstructions[parsed.index] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed.instructions.forEach((ix) => {
|
||||||
|
innerInstructions[parsed.index].push(ix);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const result = status.data.info.result;
|
const result = status.data.info.result;
|
||||||
const instructionDetails = transaction.message.instructions.map(
|
const instructionDetails = transaction.message.instructions.map(
|
||||||
(next, index) => {
|
(instruction, index) => {
|
||||||
if ("parsed" in next) {
|
let innerCards: JSX.Element[] = [];
|
||||||
switch (next.program) {
|
|
||||||
case "spl-token":
|
if (index in innerInstructions) {
|
||||||
return (
|
innerInstructions[index].forEach((ix, childIndex) => {
|
||||||
<TokenDetailsCard
|
if (typeof ix.programId === "string") {
|
||||||
key={index}
|
ix.programId = new PublicKey(ix.programId);
|
||||||
tx={transaction}
|
}
|
||||||
ix={next}
|
|
||||||
result={result}
|
let res = renderInstructionCard({
|
||||||
index={index}
|
index,
|
||||||
/>
|
ix,
|
||||||
);
|
result,
|
||||||
case "bpf-loader":
|
signature,
|
||||||
return (
|
tx: transaction,
|
||||||
<BpfLoaderDetailsCard
|
childIndex,
|
||||||
key={index}
|
raw,
|
||||||
tx={transaction}
|
});
|
||||||
ix={next}
|
|
||||||
result={result}
|
innerCards.push(res);
|
||||||
index={index}
|
});
|
||||||
/>
|
|
||||||
);
|
|
||||||
case "system":
|
|
||||||
return (
|
|
||||||
<SystemDetailsCard
|
|
||||||
key={index}
|
|
||||||
tx={transaction}
|
|
||||||
ix={next}
|
|
||||||
result={result}
|
|
||||||
index={index}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case "stake":
|
|
||||||
return (
|
|
||||||
<StakeDetailsCard
|
|
||||||
key={index}
|
|
||||||
tx={transaction}
|
|
||||||
ix={next}
|
|
||||||
result={result}
|
|
||||||
index={index}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case "spl-memo":
|
|
||||||
return (
|
|
||||||
<MemoDetailsCard
|
|
||||||
key={index}
|
|
||||||
ix={next}
|
|
||||||
result={result}
|
|
||||||
index={index}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
const props = {
|
|
||||||
ix: next,
|
|
||||||
result,
|
|
||||||
index,
|
|
||||||
raw: raw?.instructions[index],
|
|
||||||
};
|
|
||||||
return <UnknownDetailsCard key={index} {...props} />;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ix = intoTransactionInstruction(transaction, index);
|
return renderInstructionCard({
|
||||||
|
index,
|
||||||
if (!ix) {
|
ix: instruction,
|
||||||
return (
|
result,
|
||||||
<ErrorCard
|
signature,
|
||||||
key={index}
|
tx: transaction,
|
||||||
text="Could not display this instruction, please report"
|
innerCards,
|
||||||
/>
|
raw,
|
||||||
);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const props = { ix, result, index, signature };
|
|
||||||
|
|
||||||
if (isSerumInstruction(ix)) {
|
|
||||||
return <SerumDetailsCard key={index} {...props} />;
|
|
||||||
} else if (isTokenSwapInstruction(ix)) {
|
|
||||||
return <TokenSwapDetailsCard key={index} {...props} />;
|
|
||||||
} else {
|
|
||||||
return <UnknownDetailsCard key={index} {...props} />;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -540,3 +523,80 @@ function ProgramLogSection({ signature }: SignatureProps) {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderInstructionCard({
|
||||||
|
ix,
|
||||||
|
tx,
|
||||||
|
result,
|
||||||
|
index,
|
||||||
|
signature,
|
||||||
|
innerCards,
|
||||||
|
childIndex,
|
||||||
|
raw,
|
||||||
|
}: {
|
||||||
|
ix: ParsedInstruction | PartiallyDecodedInstruction;
|
||||||
|
tx: ParsedTransaction;
|
||||||
|
result: SignatureResult;
|
||||||
|
index: number;
|
||||||
|
signature: TransactionSignature;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
|
raw?: Transaction;
|
||||||
|
}) {
|
||||||
|
const key = `${index}-${childIndex}`;
|
||||||
|
|
||||||
|
if ("parsed" in ix) {
|
||||||
|
const props = {
|
||||||
|
tx,
|
||||||
|
ix,
|
||||||
|
result,
|
||||||
|
index,
|
||||||
|
innerCards,
|
||||||
|
childIndex,
|
||||||
|
key,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (ix.program) {
|
||||||
|
case "spl-token":
|
||||||
|
return <TokenDetailsCard {...props} />;
|
||||||
|
case "bpf-loader":
|
||||||
|
return <BpfLoaderDetailsCard {...props} />;
|
||||||
|
case "system":
|
||||||
|
return <SystemDetailsCard {...props} />;
|
||||||
|
case "stake":
|
||||||
|
return <StakeDetailsCard {...props} />;
|
||||||
|
case "spl-memo":
|
||||||
|
return <MemoDetailsCard {...props} />;
|
||||||
|
default:
|
||||||
|
return <UnknownDetailsCard {...props} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const transactionIx = intoTransactionInstruction(tx, ix);
|
||||||
|
|
||||||
|
if (!transactionIx) {
|
||||||
|
return (
|
||||||
|
<ErrorCard
|
||||||
|
key={key}
|
||||||
|
text="Could not display this instruction, please report"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
ix: transactionIx,
|
||||||
|
result,
|
||||||
|
index,
|
||||||
|
signature,
|
||||||
|
innerCards,
|
||||||
|
childIndex,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isSerumInstruction(transactionIx)) {
|
||||||
|
return <SerumDetailsCard key={key} {...props} />;
|
||||||
|
} else if (isTokenSwapInstruction(transactionIx)) {
|
||||||
|
return <TokenSwapDetailsCard key={key} {...props} />;
|
||||||
|
} else {
|
||||||
|
return <UnknownDetailsCard key={key} {...props} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -193,7 +193,19 @@ h4.slot-pill {
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.address-truncate {
|
.forced-truncate {
|
||||||
|
.address-truncate {
|
||||||
|
max-width: 180px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: bottom;
|
||||||
|
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-truncate, .signature-truncate {
|
||||||
@include media-breakpoint-down(md) {
|
@include media-breakpoint-down(md) {
|
||||||
max-width: 180px;
|
max-width: 180px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -205,6 +217,57 @@ h4.slot-pill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.tree,
|
||||||
|
ul.tree,
|
||||||
|
ul.tree ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.tree span.c-pointer {
|
||||||
|
color: $primary-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree ul {
|
||||||
|
margin-left: 1.0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree li {
|
||||||
|
margin-left: 0.35em;
|
||||||
|
border-left: thin solid #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree li:last-child {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree li:before {
|
||||||
|
width: 1.4em;
|
||||||
|
height: 0.6em;
|
||||||
|
margin-right: 0.1em;
|
||||||
|
vertical-align: top;
|
||||||
|
border-bottom: thin solid #808080;
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree li:last-child:before {
|
||||||
|
border-left: thin solid #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.inner-cards {
|
||||||
|
margin: 1.5rem;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: $gray-700-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td {
|
||||||
|
border-top: 1px solid $gray-800-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// work around for https://github.com/JedWatson/react-select/issues/3857
|
// work around for https://github.com/JedWatson/react-select/issues/3857
|
||||||
.search-bar__input {
|
.search-bar__input {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
|
@ -12,6 +12,8 @@ import {
|
|||||||
ParsedTransaction,
|
ParsedTransaction,
|
||||||
TransactionInstruction,
|
TransactionInstruction,
|
||||||
Transaction,
|
Transaction,
|
||||||
|
PartiallyDecodedInstruction,
|
||||||
|
ParsedInstruction,
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
import { TokenRegistry } from "tokenRegistry";
|
||||||
import { Cluster } from "providers/cluster";
|
import { Cluster } from "providers/cluster";
|
||||||
@ -79,10 +81,9 @@ export function displayAddress(address: string, cluster: Cluster): string {
|
|||||||
|
|
||||||
export function intoTransactionInstruction(
|
export function intoTransactionInstruction(
|
||||||
tx: ParsedTransaction,
|
tx: ParsedTransaction,
|
||||||
index: number
|
instruction: ParsedInstruction | PartiallyDecodedInstruction
|
||||||
): TransactionInstruction | undefined {
|
): TransactionInstruction | undefined {
|
||||||
const message = tx.message;
|
const message = tx.message;
|
||||||
const instruction = message.instructions[index];
|
|
||||||
if ("parsed" in instruction) return;
|
if ("parsed" in instruction) return;
|
||||||
|
|
||||||
const keys = [];
|
const keys = [];
|
||||||
|
Reference in New Issue
Block a user