diff --git a/explorer/src/components/TransactionDetails.tsx b/explorer/src/components/TransactionDetails.tsx index d281a2443b..6d38f33ffc 100644 --- a/explorer/src/components/TransactionDetails.tsx +++ b/explorer/src/components/TransactionDetails.tsx @@ -11,23 +11,17 @@ import { fetchDetails } from "providers/transactions/details"; import { useCluster, useClusterModal } from "providers/cluster"; import { TransactionSignature, - SystemInstruction, - SystemProgram + SystemProgram, + StakeProgram } from "@solana/web3.js"; import ClusterStatusButton from "components/ClusterStatusButton"; import { lamportsToSolString } from "utils"; import { displayAddress } from "utils/tx"; import Copyable from "./Copyable"; import { useHistory, useLocation } from "react-router-dom"; -import { TransferDetailsCard } from "./instruction/system/TransferDetailsCard"; -import { AssignDetailsCard } from "./instruction/system/AssignDetailsCard"; -import { CreateDetailsCard } from "./instruction/system/CreateDetailsCard"; -import { CreateWithSeedDetailsCard } from "./instruction/system/CreateWithSeedDetailsCard"; import { UnknownDetailsCard } from "./instruction/UnknownDetailsCard"; -import { NonceInitializeDetailsCard } from "./instruction/system/NonceInitializeDetailsCard"; -import { NonceAdvanceDetailsCard } from "./instruction/system/NonceAdvanceDetailsCard"; -import { NonceWithdrawDetailsCard } from "./instruction/system/NonceWithdrawDetailsCard"; -import { NonceAuthorizeDetailsCard } from "./instruction/system/NonceAuthorizeDetailsCard"; +import { SystemDetailsCard } from "./instruction/system/SystemDetailsCard"; +import { StakeDetailsCard } from "./instruction/stake/StakeDetailsCard"; type Props = { signature: TransactionSignature }; export default function TransactionDetails({ signature }: Props) { @@ -298,38 +292,13 @@ function InstructionsSection({ signature }: Props) { const instructionDetails = transaction.instructions.map((ix, index) => { const props = { ix, result, index }; - if (!ix.programId.equals(SystemProgram.programId)) { + if (SystemProgram.programId.equals(ix.programId)) { + return ; + } else if (StakeProgram.programId.equals(ix.programId)) { + return ; + } else { return ; } - - let systemInstructionType; - try { - systemInstructionType = SystemInstruction.decodeInstructionType(ix); - } catch (err) { - console.error(err); - return ; - } - - switch (systemInstructionType) { - case "Create": - return ; - case "Assign": - return ; - case "Transfer": - return ; - case "CreateWithSeed": - return ; - case "AdvanceNonceAccount": - return ; - case "WithdrawNonceAccount": - return ; - case "AuthorizeNonceAccount": - return ; - case "InitializeNonceAccount": - return ; - default: - return ; - } }); return ( diff --git a/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx b/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx new file mode 100644 index 0000000000..6da67477ab --- /dev/null +++ b/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx @@ -0,0 +1,94 @@ +import React from "react"; +import { + TransactionInstruction, + SignatureResult, + StakeInstruction, + StakeProgram +} from "@solana/web3.js"; +import { displayAddress } from "utils/tx"; +import { InstructionCard } from "../InstructionCard"; +import Copyable from "components/Copyable"; +import { UnknownDetailsCard } from "../UnknownDetailsCard"; + +export function AuthorizeDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + const { ix, index, result } = props; + + let params; + try { + params = StakeInstruction.decodeAuthorize(ix); + } catch (err) { + console.error(err); + return ; + } + + const stakePubkey = params.stakePubkey.toBase58(); + const authorizedPubkey = params.authorizedPubkey.toBase58(); + const newAuthorizedPubkey = params.newAuthorizedPubkey.toBase58(); + + let authorizationType; + switch (params.stakeAuthorizationType.index) { + case 0: + authorizationType = "Staker"; + break; + case 1: + authorizationType = "Withdrawer"; + break; + default: + authorizationType = "Invalid"; + break; + } + + return ( + + + Program + + + {displayAddress(StakeProgram.programId)} + + + + + + Stake Address + + + {stakePubkey} + + + + + + Old Authorized Address + + + {authorizedPubkey} + + + + + + New Authorized Address + + + {newAuthorizedPubkey} + + + + + + Authorization Type + {authorizationType} + + + ); +} diff --git a/explorer/src/components/instruction/stake/DeactivateDetailsCard.tsx b/explorer/src/components/instruction/stake/DeactivateDetailsCard.tsx new file mode 100644 index 0000000000..156c2f59e9 --- /dev/null +++ b/explorer/src/components/instruction/stake/DeactivateDetailsCard.tsx @@ -0,0 +1,66 @@ +import React from "react"; +import { + TransactionInstruction, + SignatureResult, + StakeInstruction, + StakeProgram +} from "@solana/web3.js"; +import { displayAddress } from "utils/tx"; +import { InstructionCard } from "../InstructionCard"; +import Copyable from "components/Copyable"; +import { UnknownDetailsCard } from "../UnknownDetailsCard"; + +export function DeactivateDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + const { ix, index, result } = props; + + let params; + try { + params = StakeInstruction.decodeDeactivate(ix); + } catch (err) { + console.error(err); + return ; + } + + const stakePubkey = params.stakePubkey.toBase58(); + const authorizedPubkey = params.authorizedPubkey.toBase58(); + + return ( + + + Program + + + {displayAddress(StakeProgram.programId)} + + + + + + Stake Address + + + {stakePubkey} + + + + + + Authorized Address + + + {authorizedPubkey} + + + + + ); +} diff --git a/explorer/src/components/instruction/stake/DelegateDetailsCard.tsx b/explorer/src/components/instruction/stake/DelegateDetailsCard.tsx new file mode 100644 index 0000000000..f15cb97c52 --- /dev/null +++ b/explorer/src/components/instruction/stake/DelegateDetailsCard.tsx @@ -0,0 +1,76 @@ +import React from "react"; +import { + TransactionInstruction, + SignatureResult, + StakeInstruction, + StakeProgram +} from "@solana/web3.js"; +import { displayAddress } from "utils/tx"; +import { InstructionCard } from "../InstructionCard"; +import Copyable from "components/Copyable"; +import { UnknownDetailsCard } from "../UnknownDetailsCard"; + +export function DelegateDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + const { ix, index, result } = props; + + let params; + try { + params = StakeInstruction.decodeDelegate(ix); + } catch (err) { + console.error(err); + return ; + } + + const stakePubkey = params.stakePubkey.toBase58(); + const votePubkey = params.votePubkey.toBase58(); + const authorizedPubkey = params.authorizedPubkey.toBase58(); + + return ( + + + Program + + + {displayAddress(StakeProgram.programId)} + + + + + + Stake Address + + + {stakePubkey} + + + + + + Delegated Vote Address + + + {votePubkey} + + + + + + Authorized Address + + + {authorizedPubkey} + + + + + ); +} diff --git a/explorer/src/components/instruction/stake/InitializeDetailsCard.tsx b/explorer/src/components/instruction/stake/InitializeDetailsCard.tsx new file mode 100644 index 0000000000..428f1fe702 --- /dev/null +++ b/explorer/src/components/instruction/stake/InitializeDetailsCard.tsx @@ -0,0 +1,97 @@ +import React from "react"; +import { + TransactionInstruction, + SignatureResult, + StakeInstruction, + StakeProgram +} from "@solana/web3.js"; +import { displayAddress } from "utils/tx"; +import { InstructionCard } from "../InstructionCard"; +import Copyable from "components/Copyable"; +import { UnknownDetailsCard } from "../UnknownDetailsCard"; + +export function InitializeDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + const { ix, index, result } = props; + + let params; + try { + params = StakeInstruction.decodeInitialize(ix); + } catch (err) { + console.error(err); + return ; + } + + const stakerPubkey = params.authorized.staker.toBase58(); + const withdrawerPubkey = params.authorized.withdrawer.toBase58(); + const stakePubkey = params.stakePubkey.toBase58(); + + return ( + + + Program + + + {displayAddress(StakeProgram.programId)} + + + + + + Stake Address + + + {stakePubkey} + + + + + + Authorized Staker Address + + + {stakerPubkey} + + + + + + Authorized Withdrawer Address + + + {withdrawerPubkey} + + + + + + Lockup Expiry Epoch + {params.lockup.epoch} + + + + Lockup Expiry Timestamp + + {new Date(params.lockup.unixTimestamp * 1000).toUTCString()} + + + + + Lockup Custodian Address + + + {displayAddress(params.lockup.custodian)} + + + + + ); +} diff --git a/explorer/src/components/instruction/stake/SplitDetailsCard.tsx b/explorer/src/components/instruction/stake/SplitDetailsCard.tsx new file mode 100644 index 0000000000..6ab8edaa25 --- /dev/null +++ b/explorer/src/components/instruction/stake/SplitDetailsCard.tsx @@ -0,0 +1,77 @@ +import React from "react"; +import { + TransactionInstruction, + SignatureResult, + StakeInstruction, + StakeProgram +} from "@solana/web3.js"; +import { displayAddress } from "utils/tx"; +import { lamportsToSolString } from "utils"; +import { InstructionCard } from "../InstructionCard"; +import Copyable from "components/Copyable"; +import { UnknownDetailsCard } from "../UnknownDetailsCard"; + +export function SplitDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + const { ix, index, result } = props; + + let params; + try { + params = StakeInstruction.decodeSplit(ix); + } catch (err) { + console.error(err); + return ; + } + + const stakePubkey = params.stakePubkey.toBase58(); + const authorizedPubkey = params.authorizedPubkey.toBase58(); + const splitStakePubkey = params.splitStakePubkey.toBase58(); + + return ( + + + Program + + + {displayAddress(StakeProgram.programId)} + + + + + + Stake Address + + + {stakePubkey} + + + + + + Authorized Address + + + {authorizedPubkey} + + + + + + New Stake Address + + + {splitStakePubkey} + + + + + + Split Amount (SOL) + {lamportsToSolString(params.lamports)} + + + ); +} diff --git a/explorer/src/components/instruction/stake/StakeDetailsCard.tsx b/explorer/src/components/instruction/stake/StakeDetailsCard.tsx new file mode 100644 index 0000000000..84c6580c1d --- /dev/null +++ b/explorer/src/components/instruction/stake/StakeDetailsCard.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import { + StakeInstruction, + TransactionInstruction, + SignatureResult +} from "@solana/web3.js"; + +import { UnknownDetailsCard } from "../UnknownDetailsCard"; +import { InitializeDetailsCard } from "./InitializeDetailsCard"; +import { DelegateDetailsCard } from "./DelegateDetailsCard"; +import { AuthorizeDetailsCard } from "./AuthorizeDetailsCard"; +import { SplitDetailsCard } from "./SplitDetailsCard"; +import { WithdrawDetailsCard } from "./WithdrawDetailsCard"; +import { DeactivateDetailsCard } from "./DeactivateDetailsCard"; + +type DetailsProps = { + ix: TransactionInstruction; + result: SignatureResult; + index: number; +}; + +export function StakeDetailsCard(props: DetailsProps) { + let stakeInstructionType; + try { + stakeInstructionType = StakeInstruction.decodeInstructionType(props.ix); + } catch (err) { + console.error(err); + return ; + } + + switch (stakeInstructionType) { + case "Initialize": + return ; + case "Delegate": + return ; + case "Authorize": + return ; + case "Split": + return ; + case "Withdraw": + return ; + case "Deactivate": + return ; + default: + return ; + } +} diff --git a/explorer/src/components/instruction/stake/WithdrawDetailsCard.tsx b/explorer/src/components/instruction/stake/WithdrawDetailsCard.tsx new file mode 100644 index 0000000000..68be0e0914 --- /dev/null +++ b/explorer/src/components/instruction/stake/WithdrawDetailsCard.tsx @@ -0,0 +1,82 @@ +import React from "react"; +import { + TransactionInstruction, + SignatureResult, + StakeInstruction, + StakeProgram +} from "@solana/web3.js"; +import { lamportsToSolString } from "utils"; +import { displayAddress } from "utils/tx"; +import { InstructionCard } from "../InstructionCard"; +import Copyable from "components/Copyable"; +import { UnknownDetailsCard } from "../UnknownDetailsCard"; + +export function WithdrawDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; +}) { + const { ix, index, result } = props; + + let params; + try { + params = StakeInstruction.decodeWithdraw(ix); + } catch (err) { + console.error(err); + return ; + } + + const stakePubkey = params.stakePubkey.toBase58(); + const toPubkey = params.toPubkey.toBase58(); + const authorizedPubkey = params.authorizedPubkey.toBase58(); + + return ( + + + Program + + + {displayAddress(StakeProgram.programId)} + + + + + + Stake Address + + + {stakePubkey} + + + + + + Authorized Address + + + {authorizedPubkey} + + + + + + To Address + + + {toPubkey} + + + + + + Withdraw Amount (SOL) + {lamportsToSolString(params.lamports)} + + + ); +} diff --git a/explorer/src/components/instruction/system/AssignDetailsCard.tsx b/explorer/src/components/instruction/system/AssignDetailsCard.tsx index 0bfbd37134..939872cefd 100644 --- a/explorer/src/components/instruction/system/AssignDetailsCard.tsx +++ b/explorer/src/components/instruction/system/AssignDetailsCard.tsx @@ -26,7 +26,6 @@ export function AssignDetailsCard(props: { } const from = params.fromPubkey.toBase58(); - const [fromMeta] = ix.keys; return ( - -
From Address
- {!fromMeta.isWritable && ( - Readonly - )} - {fromMeta.isSigner && ( - Signer - )} - + From Address {from} diff --git a/explorer/src/components/instruction/system/CreateDetailsCard.tsx b/explorer/src/components/instruction/system/CreateDetailsCard.tsx index 8a37bdf4e3..4b979b1d12 100644 --- a/explorer/src/components/instruction/system/CreateDetailsCard.tsx +++ b/explorer/src/components/instruction/system/CreateDetailsCard.tsx @@ -28,7 +28,6 @@ export function CreateDetailsCard(props: { const from = params.fromPubkey.toBase58(); const newKey = params.newAccountPubkey.toBase58(); - const [fromMeta, newMeta] = ix.keys; return ( - -
From Address
- {!fromMeta.isWritable && ( - Readonly - )} - {fromMeta.isSigner && ( - Signer - )} - + From Address {from} @@ -64,15 +55,7 @@ export function CreateDetailsCard(props: { - -
New Address
- {!newMeta.isWritable && ( - Readonly - )} - {newMeta.isSigner && ( - Signer - )} - + New Address {newKey} diff --git a/explorer/src/components/instruction/system/CreateWithSeedDetailsCard.tsx b/explorer/src/components/instruction/system/CreateWithSeedDetailsCard.tsx index 5ef3b4a94d..e914420aa0 100644 --- a/explorer/src/components/instruction/system/CreateWithSeedDetailsCard.tsx +++ b/explorer/src/components/instruction/system/CreateWithSeedDetailsCard.tsx @@ -29,7 +29,6 @@ export function CreateWithSeedDetailsCard(props: { const from = params.fromPubkey.toBase58(); const newKey = params.newAccountPubkey.toBase58(); const baseKey = params.basePubkey.toBase58(); - const [fromMeta, newMeta] = ix.keys; return ( - -
From Address
- {!fromMeta.isWritable && ( - Readonly - )} - {fromMeta.isSigner && ( - Signer - )} - + From Address {from} @@ -65,15 +56,7 @@ export function CreateWithSeedDetailsCard(props: { - -
New Address
- {!newMeta.isWritable && ( - Readonly - )} - {newMeta.isSigner && ( - Signer - )} - + New Address {newKey} @@ -82,15 +65,7 @@ export function CreateWithSeedDetailsCard(props: { - -
New Address
- {!newMeta.isWritable && ( - Readonly - )} - {newMeta.isSigner && ( - Signer - )} - + New Address {newKey} diff --git a/explorer/src/components/instruction/system/NonceAdvanceDetailsCard.tsx b/explorer/src/components/instruction/system/NonceAdvanceDetailsCard.tsx index 626c9f3110..c606b71fd0 100644 --- a/explorer/src/components/instruction/system/NonceAdvanceDetailsCard.tsx +++ b/explorer/src/components/instruction/system/NonceAdvanceDetailsCard.tsx @@ -27,7 +27,6 @@ export function NonceAdvanceDetailsCard(props: { const nonceKey = params.noncePubkey.toBase58(); const authorizedKey = params.authorizedPubkey.toBase58(); - const [nonceMeta, , authorizedMeta] = ix.keys; return ( - -
Nonce Address
- {!nonceMeta.isWritable && ( - Readonly - )} - {nonceMeta.isSigner && ( - Signer - )} - + Nonce Address {nonceKey} @@ -63,15 +54,7 @@ export function NonceAdvanceDetailsCard(props: { - -
Authorized Address
- {!authorizedMeta.isWritable && ( - Readonly - )} - {authorizedMeta.isSigner && ( - Signer - )} - + Authorized Address {authorizedKey} diff --git a/explorer/src/components/instruction/system/NonceAuthorizeDetailsCard.tsx b/explorer/src/components/instruction/system/NonceAuthorizeDetailsCard.tsx index 7eab86df4a..6cd399c77f 100644 --- a/explorer/src/components/instruction/system/NonceAuthorizeDetailsCard.tsx +++ b/explorer/src/components/instruction/system/NonceAuthorizeDetailsCard.tsx @@ -28,7 +28,6 @@ export function NonceAuthorizeDetailsCard(props: { const nonceKey = params.noncePubkey.toBase58(); const authorizedKey = params.authorizedPubkey.toBase58(); const newAuthorizedKey = params.newAuthorizedPubkey.toBase58(); - const [nonceMeta, authorizedMeta] = ix.keys; return ( - -
Nonce Address
- {!nonceMeta.isWritable && ( - Readonly - )} - {nonceMeta.isSigner && ( - Signer - )} - + Nonce Address {nonceKey} @@ -64,15 +55,7 @@ export function NonceAuthorizeDetailsCard(props: { - -
Authorized Address
- {!authorizedMeta.isWritable && ( - Readonly - )} - {authorizedMeta.isSigner && ( - Signer - )} - + Authorized Address {authorizedKey} diff --git a/explorer/src/components/instruction/system/NonceInitializeDetailsCard.tsx b/explorer/src/components/instruction/system/NonceInitializeDetailsCard.tsx index 2a4c2637d9..d1773568a2 100644 --- a/explorer/src/components/instruction/system/NonceInitializeDetailsCard.tsx +++ b/explorer/src/components/instruction/system/NonceInitializeDetailsCard.tsx @@ -27,7 +27,6 @@ export function NonceInitializeDetailsCard(props: { const nonceKey = params.noncePubkey.toBase58(); const authorizedKey = params.authorizedPubkey.toBase58(); - const [nonceMeta] = ix.keys; return ( - -
Nonce Address
- {!nonceMeta.isWritable && ( - Readonly - )} - {nonceMeta.isSigner && ( - Signer - )} - + Nonce Address {nonceKey} diff --git a/explorer/src/components/instruction/system/NonceWithdrawDetailsCard.tsx b/explorer/src/components/instruction/system/NonceWithdrawDetailsCard.tsx index b679e9a455..e2a8269175 100644 --- a/explorer/src/components/instruction/system/NonceWithdrawDetailsCard.tsx +++ b/explorer/src/components/instruction/system/NonceWithdrawDetailsCard.tsx @@ -30,7 +30,6 @@ export function NonceWithdrawDetailsCard(props: { const toKey = params.toPubkey.toBase58(); const authorizedKey = params.authorizedPubkey.toBase58(); const lamports = params.lamports; - const [nonceMeta, toMeta, , , authorizedMeta] = ix.keys; return ( - -
Nonce Address
- {!nonceMeta.isWritable && ( - Readonly - )} - {nonceMeta.isSigner && ( - Signer - )} - + Nonce Address {nonceKey} @@ -66,15 +57,7 @@ export function NonceWithdrawDetailsCard(props: { - -
Authorized Address
- {!authorizedMeta.isWritable && ( - Readonly - )} - {authorizedMeta.isSigner && ( - Signer - )} - + Authorized Address {authorizedKey} @@ -83,15 +66,7 @@ export function NonceWithdrawDetailsCard(props: { - -
To Address
- {!toMeta.isWritable && ( - Readonly - )} - {toMeta.isSigner && ( - Signer - )} - + To Address {toKey} diff --git a/explorer/src/components/instruction/system/SystemDetailsCard.tsx b/explorer/src/components/instruction/system/SystemDetailsCard.tsx new file mode 100644 index 0000000000..16feb8702b --- /dev/null +++ b/explorer/src/components/instruction/system/SystemDetailsCard.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { + SystemInstruction, + TransactionInstruction, + SignatureResult +} from "@solana/web3.js"; + +import { UnknownDetailsCard } from "../UnknownDetailsCard"; +import { TransferDetailsCard } from "./TransferDetailsCard"; +import { AssignDetailsCard } from "./AssignDetailsCard"; +import { CreateDetailsCard } from "./CreateDetailsCard"; +import { CreateWithSeedDetailsCard } from "./CreateWithSeedDetailsCard"; +import { NonceInitializeDetailsCard } from "./NonceInitializeDetailsCard"; +import { NonceAdvanceDetailsCard } from "./NonceAdvanceDetailsCard"; +import { NonceWithdrawDetailsCard } from "./NonceWithdrawDetailsCard"; +import { NonceAuthorizeDetailsCard } from "./NonceAuthorizeDetailsCard"; + +type DetailsProps = { + ix: TransactionInstruction; + result: SignatureResult; + index: number; +}; + +export function SystemDetailsCard(props: DetailsProps) { + let systemInstructionType; + try { + systemInstructionType = SystemInstruction.decodeInstructionType(props.ix); + } catch (err) { + console.error(err); + return ; + } + + switch (systemInstructionType) { + case "Create": + return ; + case "Assign": + return ; + case "Transfer": + return ; + case "CreateWithSeed": + return ; + case "AdvanceNonceAccount": + return ; + case "WithdrawNonceAccount": + return ; + case "AuthorizeNonceAccount": + return ; + case "InitializeNonceAccount": + return ; + default: + return ; + } +} diff --git a/explorer/src/components/instruction/system/TransferDetailsCard.tsx b/explorer/src/components/instruction/system/TransferDetailsCard.tsx index caf08e7f89..160e80e389 100644 --- a/explorer/src/components/instruction/system/TransferDetailsCard.tsx +++ b/explorer/src/components/instruction/system/TransferDetailsCard.tsx @@ -28,7 +28,6 @@ export function TransferDetailsCard(props: { const from = transfer.fromPubkey.toBase58(); const to = transfer.toPubkey.toBase58(); - const [fromMeta, toMeta] = ix.keys; return ( @@ -41,15 +40,7 @@ export function TransferDetailsCard(props: { - -
From Address
- {!fromMeta.isWritable && ( - Readonly - )} - {fromMeta.isSigner && ( - Signer - )} - + From Address {from} @@ -58,15 +49,7 @@ export function TransferDetailsCard(props: { - -
To Address
- {!toMeta.isWritable && ( - Readonly - )} - {toMeta.isSigner && ( - Signer - )} - + To Address {to}