2021-06-21 16:53:06 -07:00
|
|
|
import React from "react";
|
2022-09-24 00:10:14 -07:00
|
|
|
import { MessageCompiledInstruction, VersionedMessage } from "@solana/web3.js";
|
2021-06-21 16:53:06 -07:00
|
|
|
import { TableCardBody } from "components/common/TableCardBody";
|
2022-09-24 00:10:14 -07:00
|
|
|
import {
|
|
|
|
AddressFromLookupTableWithContext,
|
|
|
|
AddressWithContext,
|
|
|
|
programValidator,
|
|
|
|
} from "./AddressWithContext";
|
2021-06-21 16:53:06 -07:00
|
|
|
import { useCluster } from "providers/cluster";
|
2022-04-28 01:25:24 -07:00
|
|
|
import { getProgramName } from "utils/tx";
|
2021-09-12 14:02:11 -07:00
|
|
|
import { HexData } from "components/common/HexData";
|
2022-05-02 12:21:13 -07:00
|
|
|
import getInstructionCardScrollAnchorId from "utils/get-instruction-card-scroll-anchor-id";
|
|
|
|
import { useScrollAnchor } from "providers/scroll-anchor";
|
2021-06-21 16:53:06 -07:00
|
|
|
|
2022-09-24 00:10:14 -07:00
|
|
|
export function InstructionsSection({
|
|
|
|
message,
|
|
|
|
}: {
|
|
|
|
message: VersionedMessage;
|
|
|
|
}) {
|
2021-06-21 16:53:06 -07:00
|
|
|
return (
|
|
|
|
<>
|
2022-09-24 00:10:14 -07:00
|
|
|
{message.compiledInstructions.map((ix, index) => {
|
2021-06-21 16:53:06 -07:00
|
|
|
return <InstructionCard key={index} {...{ message, ix, index }} />;
|
|
|
|
})}
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function InstructionCard({
|
|
|
|
message,
|
|
|
|
ix,
|
|
|
|
index,
|
|
|
|
}: {
|
2022-09-24 00:10:14 -07:00
|
|
|
message: VersionedMessage;
|
|
|
|
ix: MessageCompiledInstruction;
|
2021-06-21 16:53:06 -07:00
|
|
|
index: number;
|
|
|
|
}) {
|
|
|
|
const [expanded, setExpanded] = React.useState(false);
|
|
|
|
const { cluster } = useCluster();
|
2022-09-24 00:10:14 -07:00
|
|
|
const programId = message.staticAccountKeys[ix.programIdIndex];
|
2022-04-28 01:25:24 -07:00
|
|
|
const programName = getProgramName(programId.toBase58(), cluster);
|
2022-05-02 12:21:13 -07:00
|
|
|
const scrollAnchorRef = useScrollAnchor(
|
|
|
|
getInstructionCardScrollAnchorId([index + 1])
|
|
|
|
);
|
2022-09-24 00:10:14 -07:00
|
|
|
const lookupsForAccountKeyIndex = [
|
|
|
|
...message.addressTableLookups.flatMap((lookup) =>
|
|
|
|
lookup.writableIndexes.map((index) => ({
|
|
|
|
lookupTableKey: lookup.accountKey,
|
|
|
|
lookupTableIndex: index,
|
|
|
|
}))
|
|
|
|
),
|
|
|
|
...message.addressTableLookups.flatMap((lookup) =>
|
|
|
|
lookup.readonlyIndexes.map((index) => ({
|
|
|
|
lookupTableKey: lookup.accountKey,
|
|
|
|
lookupTableIndex: index,
|
|
|
|
}))
|
|
|
|
),
|
|
|
|
];
|
2021-06-21 16:53:06 -07:00
|
|
|
return (
|
2022-05-02 12:21:13 -07:00
|
|
|
<div className="card" key={index} ref={scrollAnchorRef}>
|
2021-06-21 16:53:06 -07:00
|
|
|
<div className={`card-header${!expanded ? " border-bottom-none" : ""}`}>
|
|
|
|
<h3 className="card-header-title mb-0 d-flex align-items-center">
|
2021-11-28 12:49:22 -08:00
|
|
|
<span className={`badge bg-info-soft me-2`}>#{index + 1}</span>
|
2021-06-21 16:53:06 -07:00
|
|
|
{programName} Instruction
|
|
|
|
</h3>
|
|
|
|
|
|
|
|
<button
|
|
|
|
className={`btn btn-sm d-flex ${
|
|
|
|
expanded ? "btn-black active" : "btn-white"
|
|
|
|
}`}
|
|
|
|
onClick={() => setExpanded((e) => !e)}
|
|
|
|
>
|
|
|
|
{expanded ? "Collapse" : "Expand"}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
{expanded && (
|
|
|
|
<TableCardBody>
|
|
|
|
<tr>
|
|
|
|
<td>Program</td>
|
2021-11-28 12:49:22 -08:00
|
|
|
<td className="text-lg-end">
|
2021-06-21 16:53:06 -07:00
|
|
|
<AddressWithContext
|
2022-09-24 00:10:14 -07:00
|
|
|
pubkey={message.staticAccountKeys[ix.programIdIndex]}
|
2021-06-21 16:53:06 -07:00
|
|
|
validator={programValidator}
|
|
|
|
/>
|
|
|
|
</td>
|
|
|
|
</tr>
|
2022-09-24 00:10:14 -07:00
|
|
|
{ix.accountKeyIndexes.map((accountIndex, index) => {
|
|
|
|
let lookup;
|
|
|
|
if (accountIndex >= message.staticAccountKeys.length) {
|
|
|
|
const lookupIndex =
|
|
|
|
accountIndex - message.staticAccountKeys.length;
|
|
|
|
lookup = lookupsForAccountKeyIndex[lookupIndex];
|
|
|
|
}
|
|
|
|
|
2021-06-21 16:53:06 -07:00
|
|
|
return (
|
|
|
|
<tr key={index}>
|
|
|
|
<td>
|
|
|
|
<div className="d-flex align-items-start flex-column">
|
|
|
|
Account #{index + 1}
|
|
|
|
<span className="mt-1">
|
|
|
|
{accountIndex < message.header.numRequiredSignatures && (
|
2021-11-28 12:49:22 -08:00
|
|
|
<span className="badge bg-info-soft me-2">Signer</span>
|
2021-06-21 16:53:06 -07:00
|
|
|
)}
|
|
|
|
{message.isAccountWritable(accountIndex) && (
|
2021-11-28 12:49:22 -08:00
|
|
|
<span className="badge bg-danger-soft me-2">
|
2021-06-21 16:53:06 -07:00
|
|
|
Writable
|
|
|
|
</span>
|
|
|
|
)}
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</td>
|
2021-11-28 12:49:22 -08:00
|
|
|
<td className="text-lg-end">
|
2022-09-24 00:10:14 -07:00
|
|
|
{lookup === undefined ? (
|
|
|
|
<AddressWithContext
|
|
|
|
pubkey={message.staticAccountKeys[accountIndex]}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<AddressFromLookupTableWithContext
|
|
|
|
lookupTableKey={lookup.lookupTableKey}
|
|
|
|
lookupTableIndex={lookup.lookupTableIndex}
|
|
|
|
/>
|
|
|
|
)}
|
2021-06-21 16:53:06 -07:00
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
<tr>
|
|
|
|
<td>
|
|
|
|
Instruction Data <span className="text-muted">(Hex)</span>
|
|
|
|
</td>
|
2021-11-28 12:49:22 -08:00
|
|
|
<td className="text-lg-end">
|
2022-09-24 00:10:14 -07:00
|
|
|
<HexData raw={Buffer.from(ix.data)} />
|
2021-06-21 16:53:06 -07:00
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</TableCardBody>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|