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,
|
||||
ConfirmedSignatureInfo,
|
||||
ParsedInstruction,
|
||||
PartiallyDecodedInstruction,
|
||||
} from "@solana/web3.js";
|
||||
import { CacheEntry, FetchStatus } from "providers/cache";
|
||||
import {
|
||||
@ -40,6 +41,13 @@ import {
|
||||
isSerumInstruction,
|
||||
parseSerumInstructionTitle,
|
||||
} 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 }) {
|
||||
const address = pubkey.toBase58();
|
||||
@ -263,6 +271,7 @@ const TokenTransactionRow = React.memo(
|
||||
details: CacheEntry<Details> | undefined;
|
||||
}) => {
|
||||
const fetchDetails = useFetchTransactionDetails();
|
||||
const { cluster } = useCluster();
|
||||
|
||||
// Fetch details on load
|
||||
React.useEffect(() => {
|
||||
@ -309,19 +318,45 @@ const TokenTransactionRow = React.memo(
|
||||
</tr>
|
||||
);
|
||||
|
||||
const tokenInstructionNames = instructions
|
||||
.map((ix, index): string | undefined => {
|
||||
let tokenInstructionNames: InstructionType[] = [];
|
||||
|
||||
if (details?.data?.transaction) {
|
||||
const transaction = details.data.transaction;
|
||||
|
||||
tokenInstructionNames = instructions
|
||||
.map((ix, index): InstructionType | undefined => {
|
||||
let name = "Unknown";
|
||||
|
||||
const innerInstructions: (
|
||||
| ParsedInstruction
|
||||
| PartiallyDecodedInstruction
|
||||
)[] = [];
|
||||
|
||||
if (
|
||||
transaction.meta?.innerInstructions &&
|
||||
(cluster !== Cluster.MainnetBeta ||
|
||||
transaction.slot >= INNER_INSTRUCTIONS_START_SLOT)
|
||||
) {
|
||||
transaction.meta.innerInstructions.forEach((ix) => {
|
||||
if (ix.index === index) {
|
||||
ix.instructions.forEach((inner) => {
|
||||
innerInstructions.push(inner);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let transactionInstruction;
|
||||
if (details?.data?.transaction?.transaction) {
|
||||
if (transaction?.transaction) {
|
||||
transactionInstruction = intoTransactionInstruction(
|
||||
details.data.transaction.transaction,
|
||||
index
|
||||
transaction.transaction,
|
||||
ix
|
||||
);
|
||||
}
|
||||
|
||||
if ("parsed" in ix) {
|
||||
if (ix.program === "spl-token") {
|
||||
return instructionTypeName(ix, tx);
|
||||
name = instructionTypeName(ix, tx);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
@ -330,7 +365,7 @@ const TokenTransactionRow = React.memo(
|
||||
isSerumInstruction(transactionInstruction)
|
||||
) {
|
||||
try {
|
||||
return parseSerumInstructionTitle(transactionInstruction);
|
||||
name = parseSerumInstructionTitle(transactionInstruction);
|
||||
} catch (error) {
|
||||
reportError(error, { signature: tx.signature });
|
||||
return undefined;
|
||||
@ -340,7 +375,7 @@ const TokenTransactionRow = React.memo(
|
||||
isTokenSwapInstruction(transactionInstruction)
|
||||
) {
|
||||
try {
|
||||
return parseTokenSwapInstructionTitle(transactionInstruction);
|
||||
name = parseTokenSwapInstructionTitle(transactionInstruction);
|
||||
} catch (error) {
|
||||
reportError(error, { signature: tx.signature });
|
||||
return undefined;
|
||||
@ -351,16 +386,23 @@ const TokenTransactionRow = React.memo(
|
||||
account.equals(TOKEN_PROGRAM_ID)
|
||||
) >= 0
|
||||
) {
|
||||
return "Unknown (Inner)";
|
||||
}
|
||||
name = "Unknown (Inner)";
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: name,
|
||||
innerInstructions: innerInstructions,
|
||||
};
|
||||
})
|
||||
.filter((name) => name !== undefined) as string[];
|
||||
.filter((name) => name !== undefined) as InstructionType[];
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{tokenInstructionNames.map((typeName, index) => {
|
||||
{tokenInstructionNames.map((instructionType, index) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
<td className="w-1">
|
||||
@ -373,14 +415,16 @@ const TokenTransactionRow = React.memo(
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<Address pubkey={mint} link truncate />
|
||||
<td className="forced-truncate">
|
||||
<Address pubkey={mint} link truncateUnknown />
|
||||
</td>
|
||||
|
||||
<td>{typeName}</td>
|
||||
|
||||
<td>
|
||||
<Signature signature={tx.signature} link />
|
||||
<InstructionDetails instructionType={instructionType} tx={tx} />
|
||||
</td>
|
||||
|
||||
<td className="forced-truncate">
|
||||
<Signature signature={tx.signature} link truncate />
|
||||
</td>
|
||||
</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;
|
||||
raw?: 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 address = pubkey.toBase58();
|
||||
const { cluster } = useCluster();
|
||||
@ -33,6 +41,10 @@ export function Address({ pubkey, alignRight, link, raw, truncate }: Props) {
|
||||
<span className="fe fe-check-circle"></span>
|
||||
);
|
||||
|
||||
if (truncateUnknown && address === displayAddress(address, cluster)) {
|
||||
truncate = true;
|
||||
}
|
||||
|
||||
const content = (
|
||||
<>
|
||||
<span className="c-pointer font-size-tiny mr-2">{copyIcon}</span>
|
||||
|
@ -8,9 +8,10 @@ type Props = {
|
||||
signature: TransactionSignature;
|
||||
alignRight?: 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 copyToClipboard = () => navigator.clipboard.writeText(signature);
|
||||
@ -40,7 +41,10 @@ export function Signature({ signature, alignRight, link }: Props) {
|
||||
{copyButton}
|
||||
<span className="text-monospace">
|
||||
{link ? (
|
||||
<Link className="" to={clusterPath(`/tx/${signature}`)}>
|
||||
<Link
|
||||
className={truncate ? "text-truncate signature-truncate" : ""}
|
||||
to={clusterPath(`/tx/${signature}`)}
|
||||
>
|
||||
{signature}
|
||||
</Link>
|
||||
) : (
|
||||
|
@ -20,6 +20,8 @@ type InstructionProps = {
|
||||
index: number;
|
||||
ix: TransactionInstruction | ParsedInstruction;
|
||||
defaultRaw?: boolean;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
};
|
||||
|
||||
export function InstructionCard({
|
||||
@ -29,6 +31,8 @@ export function InstructionCard({
|
||||
index,
|
||||
ix,
|
||||
defaultRaw,
|
||||
innerCards,
|
||||
childIndex,
|
||||
}: InstructionProps) {
|
||||
const [resultClass] = ixResult(result, index);
|
||||
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">
|
||||
<span className={`badge badge-soft-${resultClass} mr-2`}>
|
||||
#{index + 1}
|
||||
{childIndex !== undefined ? `.${childIndex + 1}` : ""}
|
||||
</span>
|
||||
{title}
|
||||
</h3>
|
||||
@ -92,6 +97,14 @@ export function InstructionCard({
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
{innerCards && innerCards.length > 0 && (
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
Inner Instructions
|
||||
<div className="inner-cards">{innerCards}</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -7,14 +7,25 @@ export function MemoDetailsCard({
|
||||
ix,
|
||||
index,
|
||||
result,
|
||||
innerCards,
|
||||
childIndex,
|
||||
}: {
|
||||
ix: ParsedInstruction;
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const data = wrap(ix.parsed, 50);
|
||||
return (
|
||||
<InstructionCard ix={ix} index={index} result={result} title="Memo">
|
||||
<InstructionCard
|
||||
ix={ix}
|
||||
index={index}
|
||||
result={result}
|
||||
title="Memo"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Data (UTF-8)</td>
|
||||
<td className="text-lg-right">
|
||||
|
@ -29,8 +29,10 @@ export function SerumDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
signature: string;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, signature } = props;
|
||||
const { ix, index, result, signature, innerCards, childIndex } = props;
|
||||
|
||||
const { url } = useCluster();
|
||||
|
||||
@ -91,6 +93,8 @@ export function SerumDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title={`Serum: ${title || "Unknown"}`}
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
defaultRaw
|
||||
/>
|
||||
);
|
||||
|
@ -10,11 +10,15 @@ export function TokenSwapDetailsCard({
|
||||
index,
|
||||
result,
|
||||
signature,
|
||||
innerCards,
|
||||
childIndex,
|
||||
}: {
|
||||
ix: TransactionInstruction;
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
signature: string;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { url } = useCluster();
|
||||
|
||||
@ -34,6 +38,8 @@ export function TokenSwapDetailsCard({
|
||||
index={index}
|
||||
result={result}
|
||||
title={`Token Swap: ${title || "Unknown"}`}
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
defaultRaw
|
||||
/>
|
||||
);
|
||||
|
@ -10,10 +10,14 @@ export function UnknownDetailsCard({
|
||||
ix,
|
||||
index,
|
||||
result,
|
||||
innerCards,
|
||||
childIndex,
|
||||
}: {
|
||||
ix: TransactionInstruction | ParsedInstruction;
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -21,6 +25,8 @@ export function UnknownDetailsCard({
|
||||
index={index}
|
||||
result={result}
|
||||
title="Unknown"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
defaultRaw
|
||||
/>
|
||||
);
|
||||
|
@ -19,6 +19,8 @@ type DetailsProps = {
|
||||
ix: ParsedInstruction;
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
};
|
||||
|
||||
export function BpfLoaderDetailsCard(props: DetailsProps) {
|
||||
@ -50,10 +52,12 @@ type Props<T> = {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: T;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
};
|
||||
|
||||
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);
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -61,6 +65,8 @@ export function BpfLoaderWriteDetailsCard(props: Props<WriteInfo>) {
|
||||
index={index}
|
||||
result={result}
|
||||
title="BPF Loader 2: Write"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
@ -94,7 +100,7 @@ export function BpfLoaderWriteDetailsCard(props: Props<WriteInfo>) {
|
||||
}
|
||||
|
||||
export function BpfLoaderFinalizeDetailsCard(props: Props<FinalizeInfo>) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -102,6 +108,8 @@ export function BpfLoaderFinalizeDetailsCard(props: Props<FinalizeInfo>) {
|
||||
index={index}
|
||||
result={result}
|
||||
title="BPF Loader 2: Finalize"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -9,8 +9,10 @@ export function CancelOrderByClientIdDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: CancelOrderByClientId;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -18,6 +20,8 @@ export function CancelOrderByClientIdDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Serum: Cancel Order By Client Id"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Market</td>
|
||||
|
@ -9,8 +9,10 @@ export function CancelOrderDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: CancelOrder;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -18,6 +20,8 @@ export function CancelOrderDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Serum: Cancel Order"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -9,8 +9,10 @@ export function ConsumeEventsDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: ConsumeEvents;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -18,6 +20,8 @@ export function ConsumeEventsDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Serum: Consume Events"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -9,8 +9,10 @@ export function InitializeMarketDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: InitializeMarket;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -18,6 +20,8 @@ export function InitializeMarketDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Serum: Initialize Market"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -9,8 +9,10 @@ export function MatchOrdersDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: MatchOrders;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -18,6 +20,8 @@ export function MatchOrdersDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Serum: Match Orders"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -9,8 +9,10 @@ export function NewOrderDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: NewOrder;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -18,6 +20,8 @@ export function NewOrderDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Serum: New Order"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -9,8 +9,10 @@ export function SettleFundsDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: SettleFunds;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -18,6 +20,8 @@ export function SettleFundsDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Serum: Settle Funds"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -13,8 +13,10 @@ export function AuthorizeDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: AuthorizeInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -22,6 +24,8 @@ export function AuthorizeDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Stake Authorize"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -13,8 +13,10 @@ export function DeactivateDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: DeactivateInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -22,6 +24,8 @@ export function DeactivateDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Deactivate Stake"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -13,8 +13,10 @@ export function DelegateDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: DelegateInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -22,6 +24,8 @@ export function DelegateDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Delegate Stake"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -14,8 +14,10 @@ export function InitializeDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: InitializeInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -23,6 +25,8 @@ export function InitializeDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Stake Initialize"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -14,11 +14,20 @@ export function SplitDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: SplitInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
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>
|
||||
<td>Program</td>
|
||||
<td className="text-lg-right">
|
||||
|
@ -29,6 +29,8 @@ type DetailsProps = {
|
||||
ix: ParsedInstruction;
|
||||
result: SignatureResult;
|
||||
index: number;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
};
|
||||
|
||||
export function StakeDetailsCard(props: DetailsProps) {
|
||||
|
@ -14,8 +14,10 @@ export function WithdrawDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: WithdrawInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -23,6 +25,8 @@ export function WithdrawDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Withdraw Stake"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -13,8 +13,10 @@ export function AllocateDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: AllocateInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -22,6 +24,8 @@ export function AllocateDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Allocate Account"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -14,8 +14,10 @@ export function AllocateWithSeedDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: AllocateWithSeedInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -23,6 +25,8 @@ export function AllocateWithSeedDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Allocate Account w/ Seed"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -13,8 +13,10 @@ export function AssignDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: AssignInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -22,6 +24,8 @@ export function AssignDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Assign Account"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -14,8 +14,10 @@ export function AssignWithSeedDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: AssignWithSeedInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -23,6 +25,8 @@ export function AssignWithSeedDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Assign Account w/ Seed"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -14,8 +14,10 @@ export function CreateDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: CreateAccountInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -23,6 +25,8 @@ export function CreateDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Create Account"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -15,8 +15,10 @@ export function CreateWithSeedDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: CreateAccountWithSeedInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -24,6 +26,8 @@ export function CreateWithSeedDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Create Account w/ Seed"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -13,8 +13,10 @@ export function NonceAdvanceDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: AdvanceNonceInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -22,6 +24,8 @@ export function NonceAdvanceDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Advance Nonce"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -13,8 +13,10 @@ export function NonceAuthorizeDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: AuthorizeNonceInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -22,6 +24,8 @@ export function NonceAuthorizeDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Authorize Nonce"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -13,8 +13,10 @@ export function NonceInitializeDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: InitializeNonceInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -22,6 +24,8 @@ export function NonceInitializeDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Initialize Nonce"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -14,8 +14,10 @@ export function NonceWithdrawDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: WithdrawNonceInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard
|
||||
@ -23,6 +25,8 @@ export function NonceWithdrawDetailsCard(props: {
|
||||
index={index}
|
||||
result={result}
|
||||
title="Withdraw Nonce"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
|
@ -39,6 +39,8 @@ type DetailsProps = {
|
||||
ix: ParsedInstruction;
|
||||
result: SignatureResult;
|
||||
index: number;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
};
|
||||
|
||||
export function SystemDetailsCard(props: DetailsProps) {
|
||||
|
@ -14,11 +14,20 @@ export function TransferDetailsCard(props: {
|
||||
index: number;
|
||||
result: SignatureResult;
|
||||
info: TransferInfo;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
}) {
|
||||
const { ix, index, result, info } = props;
|
||||
const { ix, index, result, info, innerCards, childIndex } = props;
|
||||
|
||||
return (
|
||||
<InstructionCard ix={ix} index={index} result={result} title="Transfer">
|
||||
<InstructionCard
|
||||
ix={ix}
|
||||
index={index}
|
||||
result={result}
|
||||
title="Transfer"
|
||||
innerCards={innerCards}
|
||||
childIndex={childIndex}
|
||||
>
|
||||
<tr>
|
||||
<td>Program</td>
|
||||
<td className="text-lg-right">
|
||||
|
@ -14,7 +14,7 @@ export const PROGRAM_IDS: string[] = [
|
||||
|
||||
const INSTRUCTION_LOOKUP: { [key: number]: string } = {
|
||||
0: "Initialize Swap",
|
||||
1: "Swap",
|
||||
1: "Exchange",
|
||||
2: "Deposit",
|
||||
3: "Withdraw",
|
||||
};
|
||||
|
@ -32,6 +32,8 @@ type DetailsProps = {
|
||||
ix: ParsedInstruction;
|
||||
result: SignatureResult;
|
||||
index: number;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
};
|
||||
|
||||
export function TokenDetailsCard(props: DetailsProps) {
|
||||
@ -56,6 +58,8 @@ type InfoProps = {
|
||||
result: SignatureResult;
|
||||
index: number;
|
||||
title: string;
|
||||
innerCards?: JSX.Element[];
|
||||
childIndex?: number;
|
||||
};
|
||||
|
||||
function TokenInstruction(props: InfoProps) {
|
||||
@ -195,6 +199,8 @@ function TokenInstruction(props: InfoProps) {
|
||||
index={props.index}
|
||||
result={props.result}
|
||||
title={props.title}
|
||||
innerCards={props.innerCards}
|
||||
childIndex={props.childIndex}
|
||||
>
|
||||
{attributes}
|
||||
</InstructionCard>
|
||||
|
@ -6,12 +6,19 @@ import {
|
||||
useTransactionDetails,
|
||||
} from "providers/transactions";
|
||||
import { useFetchTransactionDetails } from "providers/transactions/details";
|
||||
import { useCluster, ClusterStatus } from "providers/cluster";
|
||||
import { useCluster, ClusterStatus, Cluster } from "providers/cluster";
|
||||
import {
|
||||
TransactionSignature,
|
||||
SystemProgram,
|
||||
SystemInstruction,
|
||||
ParsedInstruction,
|
||||
PartiallyDecodedInstruction,
|
||||
SignatureResult,
|
||||
ParsedTransaction,
|
||||
ParsedInnerInstruction,
|
||||
Transaction,
|
||||
} from "@solana/web3.js";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { lamportsToSolString } from "utils";
|
||||
import { UnknownDetailsCard } from "components/instruction/UnknownDetailsCard";
|
||||
import { SystemDetailsCard } from "components/instruction/system/SystemDetailsCard";
|
||||
@ -36,6 +43,7 @@ import { MemoDetailsCard } from "components/instruction/MemoDetailsCard";
|
||||
|
||||
const AUTO_REFRESH_INTERVAL = 2000;
|
||||
const ZERO_CONFIRMATION_BAILOUT = 5;
|
||||
export const INNER_INSTRUCTIONS_START_SLOT = 46915769;
|
||||
|
||||
type SignatureProps = {
|
||||
signature: TransactionSignature;
|
||||
@ -194,7 +202,10 @@ function StatusCard({
|
||||
const blockhash = transaction?.message.recentBlockhash;
|
||||
const isNonce = (() => {
|
||||
if (!transaction) return false;
|
||||
const ix = intoTransactionInstruction(transaction, 0);
|
||||
const ix = intoTransactionInstruction(
|
||||
transaction,
|
||||
transaction.message.instructions[0]
|
||||
);
|
||||
return (
|
||||
ix &&
|
||||
SystemProgram.programId.equals(ix.programId) &&
|
||||
@ -399,6 +410,7 @@ function AccountsCard({
|
||||
function InstructionsSection({ signature }: SignatureProps) {
|
||||
const status = useTransactionStatus(signature);
|
||||
const details = useTransactionDetails(signature);
|
||||
const { cluster } = useCluster();
|
||||
const fetchDetails = useFetchTransactionDetails();
|
||||
const refreshDetails = () => fetchDetails(signature);
|
||||
|
||||
@ -407,95 +419,66 @@ function InstructionsSection({ signature }: SignatureProps) {
|
||||
const raw = details.data.raw?.transaction;
|
||||
|
||||
const { transaction } = details.data.transaction;
|
||||
const { meta } = details.data.transaction;
|
||||
|
||||
if (transaction.message.instructions.length === 0) {
|
||||
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 instructionDetails = transaction.message.instructions.map(
|
||||
(next, index) => {
|
||||
if ("parsed" in next) {
|
||||
switch (next.program) {
|
||||
case "spl-token":
|
||||
return (
|
||||
<TokenDetailsCard
|
||||
key={index}
|
||||
tx={transaction}
|
||||
ix={next}
|
||||
result={result}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
case "bpf-loader":
|
||||
return (
|
||||
<BpfLoaderDetailsCard
|
||||
key={index}
|
||||
tx={transaction}
|
||||
ix={next}
|
||||
result={result}
|
||||
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,
|
||||
(instruction, index) => {
|
||||
let innerCards: JSX.Element[] = [];
|
||||
|
||||
if (index in innerInstructions) {
|
||||
innerInstructions[index].forEach((ix, childIndex) => {
|
||||
if (typeof ix.programId === "string") {
|
||||
ix.programId = new PublicKey(ix.programId);
|
||||
}
|
||||
|
||||
let res = renderInstructionCard({
|
||||
index,
|
||||
raw: raw?.instructions[index],
|
||||
};
|
||||
return <UnknownDetailsCard key={index} {...props} />;
|
||||
}
|
||||
ix,
|
||||
result,
|
||||
signature,
|
||||
tx: transaction,
|
||||
childIndex,
|
||||
raw,
|
||||
});
|
||||
|
||||
innerCards.push(res);
|
||||
});
|
||||
}
|
||||
|
||||
const ix = intoTransactionInstruction(transaction, index);
|
||||
|
||||
if (!ix) {
|
||||
return (
|
||||
<ErrorCard
|
||||
key={index}
|
||||
text="Could not display this instruction, please report"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
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} />;
|
||||
}
|
||||
return renderInstructionCard({
|
||||
index,
|
||||
ix: instruction,
|
||||
result,
|
||||
signature,
|
||||
tx: transaction,
|
||||
innerCards,
|
||||
raw,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
.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) {
|
||||
max-width: 180px;
|
||||
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
|
||||
.search-bar__input {
|
||||
width: 100% !important;
|
||||
|
@ -12,6 +12,8 @@ import {
|
||||
ParsedTransaction,
|
||||
TransactionInstruction,
|
||||
Transaction,
|
||||
PartiallyDecodedInstruction,
|
||||
ParsedInstruction,
|
||||
} from "@solana/web3.js";
|
||||
import { TokenRegistry } from "tokenRegistry";
|
||||
import { Cluster } from "providers/cluster";
|
||||
@ -79,10 +81,9 @@ export function displayAddress(address: string, cluster: Cluster): string {
|
||||
|
||||
export function intoTransactionInstruction(
|
||||
tx: ParsedTransaction,
|
||||
index: number
|
||||
instruction: ParsedInstruction | PartiallyDecodedInstruction
|
||||
): TransactionInstruction | undefined {
|
||||
const message = tx.message;
|
||||
const instruction = message.instructions[index];
|
||||
if ("parsed" in instruction) return;
|
||||
|
||||
const keys = [];
|
||||
|
Reference in New Issue
Block a user