Refactor instruction details components
This commit is contained in:
parent
285ae1481f
commit
13af01dcc4
|
@ -1,5 +1,4 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import bs58 from "bs58";
|
|
||||||
import {
|
import {
|
||||||
Source,
|
Source,
|
||||||
useFetchTransactionStatus,
|
useFetchTransactionStatus,
|
||||||
|
@ -10,19 +9,15 @@ import {
|
||||||
} from "../providers/transactions";
|
} from "../providers/transactions";
|
||||||
import { fetchDetails } from "providers/transactions/details";
|
import { fetchDetails } from "providers/transactions/details";
|
||||||
import { useCluster, useClusterModal } from "providers/cluster";
|
import { useCluster, useClusterModal } from "providers/cluster";
|
||||||
import {
|
import { TransactionSignature, SystemInstruction } from "@solana/web3.js";
|
||||||
TransactionSignature,
|
|
||||||
TransactionInstruction,
|
|
||||||
TransferParams,
|
|
||||||
CreateAccountParams,
|
|
||||||
SystemProgram,
|
|
||||||
SignatureResult
|
|
||||||
} from "@solana/web3.js";
|
|
||||||
import ClusterStatusButton from "components/ClusterStatusButton";
|
import ClusterStatusButton from "components/ClusterStatusButton";
|
||||||
import { lamportsToSolString } from "utils";
|
import { lamportsToSolString } from "utils";
|
||||||
import { displayAddress, decodeCreate, decodeTransfer } from "utils/tx";
|
import { displayAddress } from "utils/tx";
|
||||||
import Copyable from "./Copyable";
|
import Copyable from "./Copyable";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
|
import { TransferDetailsCard } from "./instruction/TransferDetailsCard";
|
||||||
|
import { CreateDetailsCard } from "./instruction/CreateDetailsCard";
|
||||||
|
import { RawDetailsCard } from "./instruction/RawDetailsCard";
|
||||||
|
|
||||||
type Props = { signature: TransactionSignature };
|
type Props = { signature: TransactionSignature };
|
||||||
export default function TransactionDetails({ signature }: Props) {
|
export default function TransactionDetails({ signature }: Props) {
|
||||||
|
@ -265,50 +260,6 @@ function AccountsCard({ signature }: Props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ixResult(result: SignatureResult, index: number) {
|
|
||||||
if (result.err) {
|
|
||||||
const err = result.err as any;
|
|
||||||
const ixError = err["InstructionError"];
|
|
||||||
if (ixError && Array.isArray(ixError)) {
|
|
||||||
const [errorIndex, error] = ixError;
|
|
||||||
if (Number.isInteger(errorIndex) && errorIndex === index) {
|
|
||||||
return ["warning", `Error: ${JSON.stringify(error)}`];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ["dark"];
|
|
||||||
}
|
|
||||||
return ["success"];
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstructionProps = {
|
|
||||||
title: string;
|
|
||||||
children: React.ReactNode;
|
|
||||||
result: SignatureResult;
|
|
||||||
index: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
function InstructionCard({ title, children, result, index }: InstructionProps) {
|
|
||||||
const [resultClass, errorString] = ixResult(result, index);
|
|
||||||
return (
|
|
||||||
<div className="card">
|
|
||||||
<div className="card-header">
|
|
||||||
<h3 className="card-header-title mb-0 d-flex align-items-center">
|
|
||||||
<span className={`badge badge-soft-${resultClass} mr-2`}>
|
|
||||||
#{index + 1}
|
|
||||||
</span>
|
|
||||||
{title}
|
|
||||||
</h3>
|
|
||||||
<h3 className="mb-0">
|
|
||||||
<span className="badge badge-soft-warning text-monospace">
|
|
||||||
{errorString}
|
|
||||||
</span>
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<TableCardBody>{children}</TableCardBody>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function InstructionsSection({ signature }: Props) {
|
function InstructionsSection({ signature }: Props) {
|
||||||
const status = useTransactionStatus(signature);
|
const status = useTransactionStatus(signature);
|
||||||
const details = useTransactionDetails(signature);
|
const details = useTransactionDetails(signature);
|
||||||
|
@ -325,39 +276,24 @@ function InstructionsSection({ signature }: Props) {
|
||||||
|
|
||||||
const result = status.info.result;
|
const result = status.info.result;
|
||||||
const instructionDetails = transaction.instructions.map((ix, index) => {
|
const instructionDetails = transaction.instructions.map((ix, index) => {
|
||||||
const transfer = decodeTransfer(ix);
|
const props = { ix, result, index };
|
||||||
if (transfer) {
|
|
||||||
return (
|
let instructionType;
|
||||||
<InstructionCard
|
try {
|
||||||
key={index}
|
instructionType = SystemInstruction.decodeInstructionType(ix);
|
||||||
title="Transfer"
|
} catch (err) {
|
||||||
result={result}
|
console.error(err);
|
||||||
index={index}
|
return <RawDetailsCard {...props} />;
|
||||||
>
|
|
||||||
<TransferDetails ix={ix} transfer={transfer} />
|
|
||||||
</InstructionCard>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const create = decodeCreate(ix);
|
switch (instructionType) {
|
||||||
if (create) {
|
case "Transfer":
|
||||||
return (
|
return <TransferDetailsCard {...props} />;
|
||||||
<InstructionCard
|
case "Create":
|
||||||
key={index}
|
return <CreateDetailsCard {...props} />;
|
||||||
title="Create Account"
|
default:
|
||||||
result={result}
|
return <RawDetailsCard {...props} />;
|
||||||
index={index}
|
|
||||||
>
|
|
||||||
<CreateDetails ix={ix} create={create} />
|
|
||||||
</InstructionCard>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<InstructionCard key={index} title="Raw" result={result} index={index}>
|
|
||||||
<RawDetails ix={ix} />
|
|
||||||
</InstructionCard>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -374,190 +310,6 @@ function InstructionsSection({ signature }: Props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TransferDetails({
|
|
||||||
ix,
|
|
||||||
transfer
|
|
||||||
}: {
|
|
||||||
ix: TransactionInstruction;
|
|
||||||
transfer: TransferParams;
|
|
||||||
}) {
|
|
||||||
const from = transfer.fromPubkey.toBase58();
|
|
||||||
const to = transfer.toPubkey.toBase58();
|
|
||||||
const [fromMeta, toMeta] = ix.keys;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<tr>
|
|
||||||
<td>Program</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable bottom text={SystemProgram.programId.toBase58()}>
|
|
||||||
<code>{displayAddress(SystemProgram.programId)}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div className="mr-2 d-md-inline">From Address</div>
|
|
||||||
{!fromMeta.isWritable && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
|
||||||
)}
|
|
||||||
{fromMeta.isSigner && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Signer</span>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable text={from}>
|
|
||||||
<code>{from}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div className="mr-2 d-md-inline">To Address</div>
|
|
||||||
{!toMeta.isWritable && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
|
||||||
)}
|
|
||||||
{toMeta.isSigner && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Signer</span>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable text={to}>
|
|
||||||
<code>{to}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Transfer Amount (SOL)</td>
|
|
||||||
<td className="text-right">{lamportsToSolString(transfer.lamports)}</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function CreateDetails({
|
|
||||||
ix,
|
|
||||||
create
|
|
||||||
}: {
|
|
||||||
ix: TransactionInstruction;
|
|
||||||
create: CreateAccountParams;
|
|
||||||
}) {
|
|
||||||
const from = create.fromPubkey.toBase58();
|
|
||||||
const newKey = create.newAccountPubkey.toBase58();
|
|
||||||
const [fromMeta, newMeta] = ix.keys;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<tr>
|
|
||||||
<td>Program</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable bottom text={SystemProgram.programId.toBase58()}>
|
|
||||||
<code>{displayAddress(SystemProgram.programId)}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div className="mr-2 d-md-inline">From Address</div>
|
|
||||||
{!fromMeta.isWritable && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
|
||||||
)}
|
|
||||||
{fromMeta.isSigner && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Signer</span>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable text={from}>
|
|
||||||
<code>{from}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div className="mr-2 d-md-inline">New Address</div>
|
|
||||||
{!newMeta.isWritable && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
|
||||||
)}
|
|
||||||
{newMeta.isSigner && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Signer</span>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable text={newKey}>
|
|
||||||
<code>{newKey}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Transfer Amount (SOL)</td>
|
|
||||||
<td className="text-right">{lamportsToSolString(create.lamports)}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Allocated Space (Bytes)</td>
|
|
||||||
<td className="text-right">{create.space}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Assigned Owner</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable text={create.programId.toBase58()}>
|
|
||||||
<code>{displayAddress(create.programId)}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function RawDetails({ ix }: { ix: TransactionInstruction }) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<tr>
|
|
||||||
<td>Program</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable bottom text={ix.programId.toBase58()}>
|
|
||||||
<code>{displayAddress(ix.programId)}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{ix.keys.map(({ pubkey, isSigner, isWritable }, keyIndex) => (
|
|
||||||
<tr key={keyIndex}>
|
|
||||||
<td>
|
|
||||||
<div className="mr-2 d-md-inline">Account #{keyIndex + 1}</div>
|
|
||||||
{!isWritable && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
|
||||||
)}
|
|
||||||
{isSigner && (
|
|
||||||
<span className="badge badge-soft-dark mr-1">Signer</span>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable text={pubkey.toBase58()}>
|
|
||||||
<code>{pubkey.toBase58()}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Raw Data (Base58)</td>
|
|
||||||
<td className="text-right">
|
|
||||||
<Copyable text={bs58.encode(ix.data)}>
|
|
||||||
<code>{bs58.encode(ix.data)}</code>
|
|
||||||
</Copyable>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function LoadingCard() {
|
function LoadingCard() {
|
||||||
return (
|
return (
|
||||||
<div className="card">
|
<div className="card">
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
TransactionInstruction,
|
||||||
|
SystemProgram,
|
||||||
|
SignatureResult,
|
||||||
|
SystemInstruction
|
||||||
|
} from "@solana/web3.js";
|
||||||
|
import { lamportsToSolString } from "utils";
|
||||||
|
import { displayAddress } from "utils/tx";
|
||||||
|
import { InstructionCard } from "./InstructionCard";
|
||||||
|
import Copyable from "components/Copyable";
|
||||||
|
import { RawDetailsCard } from "./RawDetailsCard";
|
||||||
|
|
||||||
|
export function CreateDetailsCard(props: {
|
||||||
|
ix: TransactionInstruction;
|
||||||
|
index: number;
|
||||||
|
result: SignatureResult;
|
||||||
|
}) {
|
||||||
|
const { ix, index, result } = props;
|
||||||
|
|
||||||
|
let create;
|
||||||
|
try {
|
||||||
|
create = SystemInstruction.decodeCreateAccount(ix);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return <RawDetailsCard {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const from = create.fromPubkey.toBase58();
|
||||||
|
const newKey = create.newAccountPubkey.toBase58();
|
||||||
|
const [fromMeta, newMeta] = ix.keys;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InstructionCard index={index} result={result} title="Create Account">
|
||||||
|
<tr>
|
||||||
|
<td>Program</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable bottom text={SystemProgram.programId.toBase58()}>
|
||||||
|
<code>{displayAddress(SystemProgram.programId)}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div className="mr-2 d-md-inline">From Address</div>
|
||||||
|
{!fromMeta.isWritable && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
||||||
|
)}
|
||||||
|
{fromMeta.isSigner && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Signer</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable text={from}>
|
||||||
|
<code>{from}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div className="mr-2 d-md-inline">New Address</div>
|
||||||
|
{!newMeta.isWritable && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
||||||
|
)}
|
||||||
|
{newMeta.isSigner && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Signer</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable text={newKey}>
|
||||||
|
<code>{newKey}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Transfer Amount (SOL)</td>
|
||||||
|
<td className="text-right">{lamportsToSolString(create.lamports)}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Allocated Space (Bytes)</td>
|
||||||
|
<td className="text-right">{create.space}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Assigned Owner</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable text={create.programId.toBase58()}>
|
||||||
|
<code>{displayAddress(create.programId)}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</InstructionCard>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import React from "react";
|
||||||
|
import { SignatureResult } from "@solana/web3.js";
|
||||||
|
|
||||||
|
type InstructionProps = {
|
||||||
|
title: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
result: SignatureResult;
|
||||||
|
index: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function InstructionCard({
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
result,
|
||||||
|
index
|
||||||
|
}: InstructionProps) {
|
||||||
|
const [resultClass, errorString] = ixResult(result, index);
|
||||||
|
return (
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-header">
|
||||||
|
<h3 className="card-header-title mb-0 d-flex align-items-center">
|
||||||
|
<span className={`badge badge-soft-${resultClass} mr-2`}>
|
||||||
|
#{index + 1}
|
||||||
|
</span>
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
<h3 className="mb-0">
|
||||||
|
<span className="badge badge-soft-warning text-monospace">
|
||||||
|
{errorString}
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div className="table-responsive mb-0">
|
||||||
|
<table className="table table-sm table-nowrap card-table">
|
||||||
|
<tbody className="list">{children}</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ixResult(result: SignatureResult, index: number) {
|
||||||
|
if (result.err) {
|
||||||
|
const err = result.err as any;
|
||||||
|
const ixError = err["InstructionError"];
|
||||||
|
if (ixError && Array.isArray(ixError)) {
|
||||||
|
const [errorIndex, error] = ixError;
|
||||||
|
if (Number.isInteger(errorIndex) && errorIndex === index) {
|
||||||
|
return ["warning", `Error: ${JSON.stringify(error)}`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ["dark"];
|
||||||
|
}
|
||||||
|
return ["success"];
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
import React from "react";
|
||||||
|
import bs58 from "bs58";
|
||||||
|
import { TransactionInstruction, SignatureResult } from "@solana/web3.js";
|
||||||
|
import { displayAddress } from "utils/tx";
|
||||||
|
import { InstructionCard } from "./InstructionCard";
|
||||||
|
import Copyable from "components/Copyable";
|
||||||
|
|
||||||
|
export function RawDetailsCard({
|
||||||
|
ix,
|
||||||
|
index,
|
||||||
|
result
|
||||||
|
}: {
|
||||||
|
ix: TransactionInstruction;
|
||||||
|
index: number;
|
||||||
|
result: SignatureResult;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<InstructionCard index={index} result={result} title="Raw">
|
||||||
|
<tr>
|
||||||
|
<td>Program</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable bottom text={ix.programId.toBase58()}>
|
||||||
|
<code>{displayAddress(ix.programId)}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{ix.keys.map(({ pubkey, isSigner, isWritable }, keyIndex) => (
|
||||||
|
<tr key={keyIndex}>
|
||||||
|
<td>
|
||||||
|
<div className="mr-2 d-md-inline">Account #{keyIndex + 1}</div>
|
||||||
|
{!isWritable && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
||||||
|
)}
|
||||||
|
{isSigner && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Signer</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable text={pubkey.toBase58()}>
|
||||||
|
<code>{pubkey.toBase58()}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Raw Data (Base58)</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable text={bs58.encode(ix.data)}>
|
||||||
|
<code>{bs58.encode(ix.data)}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</InstructionCard>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
TransactionInstruction,
|
||||||
|
SystemProgram,
|
||||||
|
SignatureResult,
|
||||||
|
SystemInstruction
|
||||||
|
} from "@solana/web3.js";
|
||||||
|
import { lamportsToSolString } from "utils";
|
||||||
|
import { displayAddress } from "utils/tx";
|
||||||
|
import { InstructionCard } from "./InstructionCard";
|
||||||
|
import Copyable from "components/Copyable";
|
||||||
|
import { RawDetailsCard } from "./RawDetailsCard";
|
||||||
|
|
||||||
|
export function TransferDetailsCard(props: {
|
||||||
|
ix: TransactionInstruction;
|
||||||
|
index: number;
|
||||||
|
result: SignatureResult;
|
||||||
|
}) {
|
||||||
|
const { ix, index, result } = props;
|
||||||
|
|
||||||
|
let transfer;
|
||||||
|
try {
|
||||||
|
transfer = SystemInstruction.decodeTransfer(ix);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return <RawDetailsCard {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const from = transfer.fromPubkey.toBase58();
|
||||||
|
const to = transfer.toPubkey.toBase58();
|
||||||
|
const [fromMeta, toMeta] = ix.keys;
|
||||||
|
return (
|
||||||
|
<InstructionCard index={index} result={result} title="Transfer">
|
||||||
|
<tr>
|
||||||
|
<td>Program</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable bottom text={SystemProgram.programId.toBase58()}>
|
||||||
|
<code>{displayAddress(SystemProgram.programId)}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div className="mr-2 d-md-inline">From Address</div>
|
||||||
|
{!fromMeta.isWritable && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
||||||
|
)}
|
||||||
|
{fromMeta.isSigner && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Signer</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable text={from}>
|
||||||
|
<code>{from}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div className="mr-2 d-md-inline">To Address</div>
|
||||||
|
{!toMeta.isWritable && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Readonly</span>
|
||||||
|
)}
|
||||||
|
{toMeta.isSigner && (
|
||||||
|
<span className="badge badge-soft-dark mr-1">Signer</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-right">
|
||||||
|
<Copyable text={to}>
|
||||||
|
<code>{to}</code>
|
||||||
|
</Copyable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Transfer Amount (SOL)</td>
|
||||||
|
<td className="text-right">{lamportsToSolString(transfer.lamports)}</td>
|
||||||
|
</tr>
|
||||||
|
</InstructionCard>
|
||||||
|
);
|
||||||
|
}
|
|
@ -4,10 +4,6 @@ import {
|
||||||
StakeProgram,
|
StakeProgram,
|
||||||
VOTE_PROGRAM_ID,
|
VOTE_PROGRAM_ID,
|
||||||
BpfLoader,
|
BpfLoader,
|
||||||
TransferParams,
|
|
||||||
SystemInstruction,
|
|
||||||
CreateAccountParams,
|
|
||||||
TransactionInstruction,
|
|
||||||
SYSVAR_CLOCK_PUBKEY,
|
SYSVAR_CLOCK_PUBKEY,
|
||||||
SYSVAR_RENT_PUBKEY,
|
SYSVAR_RENT_PUBKEY,
|
||||||
SYSVAR_REWARDS_PUBKEY,
|
SYSVAR_REWARDS_PUBKEY,
|
||||||
|
@ -53,31 +49,3 @@ export function displayAddress(pubkey: PublicKey): string {
|
||||||
address
|
address
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decodeTransfer(
|
|
||||||
ix: TransactionInstruction
|
|
||||||
): TransferParams | null {
|
|
||||||
if (!ix.programId.equals(SystemProgram.programId)) return null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (SystemInstruction.decodeInstructionType(ix) !== "Transfer") return null;
|
|
||||||
return SystemInstruction.decodeTransfer(ix);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(ix, err);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function decodeCreate(
|
|
||||||
ix: TransactionInstruction
|
|
||||||
): CreateAccountParams | null {
|
|
||||||
if (!ix.programId.equals(SystemProgram.programId)) return null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (SystemInstruction.decodeInstructionType(ix) !== "Create") return null;
|
|
||||||
return SystemInstruction.decodeCreateAccount(ix);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(ix, err);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue