refresh(signature)} text="Not Found" />;
}
const { info } = status;
@@ -191,7 +194,7 @@ function AccountsCard({ signature }: Props) {
return null;
} else if (!details) {
return (
-
@@ -199,14 +202,14 @@ function AccountsCard({ signature }: Props) {
} else if (details.fetchStatus === FetchStatus.Fetching) {
return ;
} else if (details?.fetchStatus === FetchStatus.FetchFailed) {
- return ;
+ return ;
} else if (!details.transaction || !message) {
- return ;
+ return ;
}
const { meta } = details.transaction;
if (!meta) {
- return ;
+ return ;
}
const accountRows = message.accountKeys.map((pubkey, index) => {
@@ -228,7 +231,7 @@ function AccountsCard({ signature }: Props) {
- {displayAddress(pubkey)}
+ {displayAddress(pubkey.toBase58())}
|
{renderChange()} |
@@ -284,7 +287,7 @@ function InstructionsSection({ signature }: Props) {
const { transaction } = details.transaction;
if (transaction.instructions.length === 0) {
- return ;
+ return ;
}
const result = status.info.result;
@@ -313,43 +316,3 @@ function InstructionsSection({ signature }: Props) {
>
);
}
-
-function LoadingCard() {
- return (
-
- );
-}
-
-function RetryCard({ retry, text }: { retry: () => void; text: string }) {
- return (
-
-
- {text}
-
- Try Again
-
-
-
-
- Try Again
-
-
-
-
- );
-}
-
-function TableCardBody({ children }: { children: React.ReactNode }) {
- return (
-
- );
-}
diff --git a/explorer/src/components/account/StakeAccountDetailsCard.tsx b/explorer/src/components/account/StakeAccountDetailsCard.tsx
new file mode 100644
index 0000000000..862cedad80
--- /dev/null
+++ b/explorer/src/components/account/StakeAccountDetailsCard.tsx
@@ -0,0 +1,121 @@
+import React from "react";
+import { StakeAccount } from "solana-sdk-wasm";
+import TableCardBody from "components/common/TableCardBody";
+import { lamportsToSolString } from "utils";
+import Copyable from "components/Copyable";
+import { displayAddress } from "utils/tx";
+
+export function StakeAccountDetailsCard({
+ account
+}: {
+ account: StakeAccount;
+}) {
+ const { meta, stake } = account;
+ return (
+
+
+
+ Stake Account
+
+
+
+
+ State |
+ {account.displayState()} |
+
+
+ {meta && (
+ <>
+
+ Rent Reserve (SOL) |
+
+ {lamportsToSolString(meta.rentExemptReserve)}
+ |
+
+
+
+ Authorized Staker Address |
+
+
+ {meta.authorized.staker.toBase58()}
+
+ |
+
+
+
+ Authorized Withdrawer Address |
+
+
+ {meta.authorized.withdrawer.toBase58()}
+
+ |
+
+
+
+ Lockup Expiry Epoch |
+ {meta.lockup.epoch} |
+
+
+
+ Lockup Expiry Timestamp |
+
+ {new Date(meta.lockup.unixTimestamp).toUTCString()}
+ |
+
+
+
+ Lockup Custodian Address |
+
+
+
+ {displayAddress(meta.lockup.custodian.toBase58())}
+
+
+ |
+
+ >
+ )}
+
+ {stake && (
+ <>
+
+ Delegated Stake (SOL) |
+
+ {lamportsToSolString(stake.delegation.stake)}
+ |
+
+
+
+ Delegated Vote Address |
+
+
+
+ {displayAddress(stake.delegation.voterPubkey.toBase58())}
+
+
+ |
+
+
+
+ Activation Epoch |
+
+ {stake.delegation.isBootstrapStake()
+ ? "-"
+ : stake.delegation.activationEpoch}
+ |
+
+
+
+ Deactivation Epoch |
+
+ {stake.delegation.isDeactivated()
+ ? stake.delegation.deactivationEpoch
+ : "-"}
+ |
+
+ >
+ )}
+
+
+ );
+}
diff --git a/explorer/src/components/common/ErrorCard.tsx b/explorer/src/components/common/ErrorCard.tsx
new file mode 100644
index 0000000000..81838ab394
--- /dev/null
+++ b/explorer/src/components/common/ErrorCard.tsx
@@ -0,0 +1,33 @@
+import React from "react";
+
+export default function ErrorCard({
+ retry,
+ text
+}: {
+ retry?: () => void;
+ text: string;
+}) {
+ return (
+
+
+ {text}
+ {retry && (
+ <>
+
+ Try Again
+
+
+
+
+ Try Again
+
+
+ >
+ )}
+
+
+ );
+}
diff --git a/explorer/src/components/common/LoadingCard.tsx b/explorer/src/components/common/LoadingCard.tsx
new file mode 100644
index 0000000000..f0088dd074
--- /dev/null
+++ b/explorer/src/components/common/LoadingCard.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+
+export default function LoadingCard() {
+ return (
+
+ );
+}
diff --git a/explorer/src/components/common/TableCardBody.tsx b/explorer/src/components/common/TableCardBody.tsx
new file mode 100644
index 0000000000..b2e35f2d13
--- /dev/null
+++ b/explorer/src/components/common/TableCardBody.tsx
@@ -0,0 +1,15 @@
+import React from "react";
+
+export default function TableCardBody({
+ children
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+ );
+}
diff --git a/explorer/src/components/instruction/RawDetails.tsx b/explorer/src/components/instruction/RawDetails.tsx
index e4a86ff81a..412f2b46aa 100644
--- a/explorer/src/components/instruction/RawDetails.tsx
+++ b/explorer/src/components/instruction/RawDetails.tsx
@@ -19,7 +19,7 @@ export function RawDetails({ ix }: { ix: TransactionInstruction }) {
Program |
- {displayAddress(ix.programId)}
+ {displayAddress(ix.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx b/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx
index 6da67477ab..00f760dc01 100644
--- a/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx
+++ b/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx
@@ -53,7 +53,7 @@ export function AuthorizeDetailsCard(props: {
Program |
- {displayAddress(StakeProgram.programId)}
+ {displayAddress(StakeProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/stake/DeactivateDetailsCard.tsx b/explorer/src/components/instruction/stake/DeactivateDetailsCard.tsx
index 156c2f59e9..d348be4e93 100644
--- a/explorer/src/components/instruction/stake/DeactivateDetailsCard.tsx
+++ b/explorer/src/components/instruction/stake/DeactivateDetailsCard.tsx
@@ -39,7 +39,7 @@ export function DeactivateDetailsCard(props: {
Program |
- {displayAddress(StakeProgram.programId)}
+ {displayAddress(StakeProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/stake/DelegateDetailsCard.tsx b/explorer/src/components/instruction/stake/DelegateDetailsCard.tsx
index f15cb97c52..f6de80dfb0 100644
--- a/explorer/src/components/instruction/stake/DelegateDetailsCard.tsx
+++ b/explorer/src/components/instruction/stake/DelegateDetailsCard.tsx
@@ -40,7 +40,7 @@ export function DelegateDetailsCard(props: {
Program |
- {displayAddress(StakeProgram.programId)}
+ {displayAddress(StakeProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/stake/InitializeDetailsCard.tsx b/explorer/src/components/instruction/stake/InitializeDetailsCard.tsx
index 428f1fe702..05fd5ca114 100644
--- a/explorer/src/components/instruction/stake/InitializeDetailsCard.tsx
+++ b/explorer/src/components/instruction/stake/InitializeDetailsCard.tsx
@@ -40,7 +40,7 @@ export function InitializeDetailsCard(props: {
Program |
- {displayAddress(StakeProgram.programId)}
+ {displayAddress(StakeProgram.programId.toBase58())}
|
@@ -88,7 +88,7 @@ export function InitializeDetailsCard(props: {
Lockup Custodian Address |
- {displayAddress(params.lockup.custodian)}
+ {displayAddress(params.lockup.custodian.toBase58())}
|
diff --git a/explorer/src/components/instruction/stake/SplitDetailsCard.tsx b/explorer/src/components/instruction/stake/SplitDetailsCard.tsx
index 6ab8edaa25..cf51d8f4e0 100644
--- a/explorer/src/components/instruction/stake/SplitDetailsCard.tsx
+++ b/explorer/src/components/instruction/stake/SplitDetailsCard.tsx
@@ -36,7 +36,7 @@ export function SplitDetailsCard(props: {
Program |
- {displayAddress(StakeProgram.programId)}
+ {displayAddress(StakeProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/stake/WithdrawDetailsCard.tsx b/explorer/src/components/instruction/stake/WithdrawDetailsCard.tsx
index 68be0e0914..39ccd31e19 100644
--- a/explorer/src/components/instruction/stake/WithdrawDetailsCard.tsx
+++ b/explorer/src/components/instruction/stake/WithdrawDetailsCard.tsx
@@ -41,7 +41,7 @@ export function WithdrawDetailsCard(props: {
Program |
- {displayAddress(StakeProgram.programId)}
+ {displayAddress(StakeProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/AllocateDetailsCard.tsx b/explorer/src/components/instruction/system/AllocateDetailsCard.tsx
index 55fd133992..858be1a850 100644
--- a/explorer/src/components/instruction/system/AllocateDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/AllocateDetailsCard.tsx
@@ -38,7 +38,7 @@ export function AllocateDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/AllocateWithSeedDetailsCard.tsx b/explorer/src/components/instruction/system/AllocateWithSeedDetailsCard.tsx
index 644690ad68..fd9eaac88e 100644
--- a/explorer/src/components/instruction/system/AllocateWithSeedDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/AllocateWithSeedDetailsCard.tsx
@@ -39,7 +39,7 @@ export function AllocateWithSeedDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
@@ -80,7 +80,7 @@ export function AllocateWithSeedDetailsCard(props: {
Assigned Owner |
- {displayAddress(params.programId)}
+ {displayAddress(params.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/AssignDetailsCard.tsx b/explorer/src/components/instruction/system/AssignDetailsCard.tsx
index 6a2a1c94f3..2518fc89a4 100644
--- a/explorer/src/components/instruction/system/AssignDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/AssignDetailsCard.tsx
@@ -38,7 +38,7 @@ export function AssignDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
@@ -56,7 +56,7 @@ export function AssignDetailsCard(props: {
Assigned Owner |
- {displayAddress(params.programId)}
+ {displayAddress(params.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/AssignWithSeedDetailsCard.tsx b/explorer/src/components/instruction/system/AssignWithSeedDetailsCard.tsx
index e98f639fc8..2d9459e13e 100644
--- a/explorer/src/components/instruction/system/AssignWithSeedDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/AssignWithSeedDetailsCard.tsx
@@ -39,7 +39,7 @@ export function AssignWithSeedDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
@@ -75,7 +75,7 @@ export function AssignWithSeedDetailsCard(props: {
Assigned Owner |
- {displayAddress(params.programId)}
+ {displayAddress(params.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/CreateDetailsCard.tsx b/explorer/src/components/instruction/system/CreateDetailsCard.tsx
index 4b979b1d12..f03143e4af 100644
--- a/explorer/src/components/instruction/system/CreateDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/CreateDetailsCard.tsx
@@ -40,7 +40,7 @@ export function CreateDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
@@ -77,7 +77,7 @@ export function CreateDetailsCard(props: {
Assigned Owner |
- {displayAddress(params.programId)}
+ {displayAddress(params.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/CreateWithSeedDetailsCard.tsx b/explorer/src/components/instruction/system/CreateWithSeedDetailsCard.tsx
index e914420aa0..6fe24125b9 100644
--- a/explorer/src/components/instruction/system/CreateWithSeedDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/CreateWithSeedDetailsCard.tsx
@@ -41,7 +41,7 @@ export function CreateWithSeedDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
@@ -105,7 +105,7 @@ export function CreateWithSeedDetailsCard(props: {
Assigned Owner |
- {displayAddress(params.programId)}
+ {displayAddress(params.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/NonceAdvanceDetailsCard.tsx b/explorer/src/components/instruction/system/NonceAdvanceDetailsCard.tsx
index c606b71fd0..6ba33213a7 100644
--- a/explorer/src/components/instruction/system/NonceAdvanceDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/NonceAdvanceDetailsCard.tsx
@@ -39,7 +39,7 @@ export function NonceAdvanceDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/NonceAuthorizeDetailsCard.tsx b/explorer/src/components/instruction/system/NonceAuthorizeDetailsCard.tsx
index 6cd399c77f..0f33f7da7f 100644
--- a/explorer/src/components/instruction/system/NonceAuthorizeDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/NonceAuthorizeDetailsCard.tsx
@@ -40,7 +40,7 @@ export function NonceAuthorizeDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/NonceInitializeDetailsCard.tsx b/explorer/src/components/instruction/system/NonceInitializeDetailsCard.tsx
index d1773568a2..fbd922ae86 100644
--- a/explorer/src/components/instruction/system/NonceInitializeDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/NonceInitializeDetailsCard.tsx
@@ -39,7 +39,7 @@ export function NonceInitializeDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/NonceWithdrawDetailsCard.tsx b/explorer/src/components/instruction/system/NonceWithdrawDetailsCard.tsx
index e2a8269175..3fa90bc699 100644
--- a/explorer/src/components/instruction/system/NonceWithdrawDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/NonceWithdrawDetailsCard.tsx
@@ -42,7 +42,7 @@ export function NonceWithdrawDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
diff --git a/explorer/src/components/instruction/system/TransferDetailsCard.tsx b/explorer/src/components/instruction/system/TransferDetailsCard.tsx
index 160e80e389..ad2cba05fd 100644
--- a/explorer/src/components/instruction/system/TransferDetailsCard.tsx
+++ b/explorer/src/components/instruction/system/TransferDetailsCard.tsx
@@ -34,7 +34,7 @@ export function TransferDetailsCard(props: {
Program |
- {displayAddress(SystemProgram.programId)}
+ {displayAddress(SystemProgram.programId.toBase58())}
|
diff --git a/explorer/src/providers/accounts.tsx b/explorer/src/providers/accounts.tsx
index 93df5571be..47c0e9abaf 100644
--- a/explorer/src/providers/accounts.tsx
+++ b/explorer/src/providers/accounts.tsx
@@ -4,7 +4,8 @@ import {
Connection,
TransactionSignature,
TransactionError,
- SignatureStatus
+ SignatureStatus,
+ StakeProgram
} from "@solana/web3.js";
import { useQuery } from "../utils/url";
import { useCluster, ClusterStatus } from "./cluster";
@@ -27,6 +28,7 @@ export interface Details {
executable: boolean;
owner: PublicKey;
space: number;
+ data?: Buffer;
}
export interface Account {
@@ -192,10 +194,18 @@ async function fetchAccountInfo(
fetchStatus = Status.NotFound;
} else {
lamports = result.lamports;
+ let data = undefined;
+
+ // Only save data in memory if we can decode it
+ if (result.owner.equals(StakeProgram.programId)) {
+ data = result.data;
+ }
+
details = {
space: result.data.length,
executable: result.executable,
- owner: result.owner
+ owner: result.owner,
+ data
};
fetchStatus = Status.FetchingHistory;
fetchAccountHistory(dispatch, pubkey, url);
diff --git a/explorer/src/utils/tx.ts b/explorer/src/utils/tx.ts
index 7f00dbd688..8721f98e3e 100644
--- a/explorer/src/utils/tx.ts
+++ b/explorer/src/utils/tx.ts
@@ -1,5 +1,4 @@
import {
- PublicKey,
SystemProgram,
StakeProgram,
VOTE_PROGRAM_ID,
@@ -40,8 +39,7 @@ const SYSVAR_IDS = {
[SYSVAR_STAKE_HISTORY_PUBKEY.toBase58()]: "SYSVAR_STAKE_HISTORY"
};
-export function displayAddress(pubkey: PublicKey): string {
- const address = pubkey.toBase58();
+export function displayAddress(address: string): string {
return (
PROGRAM_IDS[address] ||
LOADER_IDS[address] ||
diff --git a/explorer/wasm/.gitignore b/explorer/wasm/.gitignore
new file mode 100644
index 0000000000..7f384f961b
--- /dev/null
+++ b/explorer/wasm/.gitignore
@@ -0,0 +1,16 @@
+/target/
+
+**/*.rs.bk
+.cargo
+
+/config/
+
+# log files
+*.log
+log-*.txt
+log-*/
+
+# intellij files
+/.idea/
+/solana.iml
+/.vscode/
diff --git a/explorer/wasm/Cargo.lock b/explorer/wasm/Cargo.lock
new file mode 100644
index 0000000000..86ed5fbbaf
--- /dev/null
+++ b/explorer/wasm/Cargo.lock
@@ -0,0 +1,179 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "bincode"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
+dependencies = [
+ "byteorder",
+ "serde",
+]
+
+[[package]]
+name = "bs58"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb"
+
+[[package]]
+name = "bumpalo"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
+
+[[package]]
+name = "byteorder"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "js-sys"
+version = "0.3.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa5a448de267e7358beaf4a5d849518fe9a0c13fce7afd44b06e68550e5562a7"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "log"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42934bc9c8ab0d3b273a16d8551c8f0fcff46be73276ca083ec2414c15c4ba5e"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.110"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.110"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "solana-sdk-wasm"
+version = "1.2.0"
+dependencies = [
+ "bincode",
+ "bs58",
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4696caa4048ac7ce2bcd2e484b3cef88c1004e41b8e945a277e2c25dc0b72060"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3c7d40d09cdbf0f4895ae58cf57d92e1e57a9dd8ed2e8390514b54a47cc5551"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3972e137ebf830900db522d6c8fd74d1900dcfc733462e9a12e942b00b4ac94"
+dependencies = [
+ "bumpalo",
+ "lazy_static",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad"
diff --git a/explorer/wasm/Cargo.toml b/explorer/wasm/Cargo.toml
new file mode 100644
index 0000000000..70d712e0a1
--- /dev/null
+++ b/explorer/wasm/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+name = "solana-sdk-wasm"
+version = "1.2.0"
+description = "Solana SDK Wasm"
+authors = ["Solana Maintainers "]
+repository = "https://github.com/solana-labs/solana"
+homepage = "https://solana.com/"
+license = "Apache-2.0"
+edition = "2018"
+
+[lib]
+name = "solana_sdk_wasm"
+crate-type = ["cdylib", "rlib"]
+
+[dependencies]
+bincode = "1.2.1"
+bs58 = "0.3.1"
+serde = { version = "1.0", features = ["derive"] }
+wasm-bindgen = "0.2"
+js-sys = "0.3"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[profile.release]
+# Tell `rustc` to optimize for small code size.
+opt-level = "s"
\ No newline at end of file
diff --git a/explorer/wasm/README.md b/explorer/wasm/README.md
new file mode 100644
index 0000000000..7074e7fe6e
--- /dev/null
+++ b/explorer/wasm/README.md
@@ -0,0 +1,15 @@
+# solana-sdk-wasm
+
+Temporary location for a Solana SDK for decoding account data in WebAssembly
+
+### Install
+
+cargo install wasm-pack
+
+### Build
+
+wasm-pack build
+
+### Release
+
+Add built files in `./pkg` to source control
\ No newline at end of file
diff --git a/explorer/wasm/pkg/package.json b/explorer/wasm/pkg/package.json
new file mode 100644
index 0000000000..f0ea2ed836
--- /dev/null
+++ b/explorer/wasm/pkg/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "solana-sdk-wasm",
+ "collaborators": [
+ "Solana Maintainers "
+ ],
+ "description": "Solana SDK Wasm",
+ "version": "1.2.0",
+ "license": "Apache-2.0",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/solana-labs/solana"
+ },
+ "files": [
+ "solana_sdk_wasm_bg.wasm",
+ "solana_sdk_wasm.js",
+ "solana_sdk_wasm.d.ts"
+ ],
+ "module": "solana_sdk_wasm.js",
+ "homepage": "https://solana.com/",
+ "types": "solana_sdk_wasm.d.ts",
+ "sideEffects": false
+}
\ No newline at end of file
diff --git a/explorer/wasm/pkg/solana_sdk_wasm.d.ts b/explorer/wasm/pkg/solana_sdk_wasm.d.ts
new file mode 100644
index 0000000000..fc17502628
--- /dev/null
+++ b/explorer/wasm/pkg/solana_sdk_wasm.d.ts
@@ -0,0 +1,140 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+*/
+export enum StakeState {
+ Uninitialized,
+ Initialized,
+ Delegated,
+ RewardsPool,
+}
+/**
+*/
+export class Authorized {
+ free(): void;
+/**
+* @returns {Pubkey}
+*/
+ staker: Pubkey;
+/**
+* @returns {Pubkey}
+*/
+ withdrawer: Pubkey;
+}
+/**
+*/
+export class Delegation {
+ free(): void;
+/**
+* @returns {boolean}
+*/
+ isBootstrapStake(): boolean;
+/**
+* @returns {boolean}
+*/
+ isDeactivated(): boolean;
+/**
+* @returns {number}
+*/
+ readonly activationEpoch: number;
+/**
+* @returns {number}
+*/
+ readonly deactivationEpoch: number;
+/**
+* @returns {number}
+*/
+ readonly stake: number;
+/**
+* @returns {Pubkey}
+*/
+ readonly voterPubkey: Pubkey;
+/**
+* @returns {number}
+*/
+ readonly warmupCooldownRate: number;
+}
+/**
+*/
+export class Lockup {
+ free(): void;
+/**
+* custodian signature on a transaction exempts the operation from
+* lockup constraints
+* @returns {Pubkey}
+*/
+ custodian: Pubkey;
+/**
+* @returns {number}
+*/
+ readonly epoch: number;
+/**
+* @returns {number}
+*/
+ readonly unixTimestamp: number;
+}
+/**
+*/
+export class Meta {
+ free(): void;
+/**
+* @returns {Authorized}
+*/
+ authorized: Authorized;
+/**
+* @returns {Lockup}
+*/
+ lockup: Lockup;
+/**
+* @returns {number}
+*/
+ readonly rentExemptReserve: number;
+}
+/**
+*/
+export class Pubkey {
+ free(): void;
+/**
+* @returns {string}
+*/
+ toBase58(): string;
+}
+/**
+*/
+export class Stake {
+ free(): void;
+/**
+* @returns {number}
+*/
+ readonly creditsObserved: number;
+/**
+* @returns {Delegation}
+*/
+ delegation: Delegation;
+}
+/**
+*/
+export class StakeAccount {
+ free(): void;
+/**
+* @param {Uint8Array} data
+* @returns {StakeAccount}
+*/
+ static fromAccountData(data: Uint8Array): StakeAccount;
+/**
+* @returns {string}
+*/
+ displayState(): string;
+/**
+* @returns {Meta | undefined}
+*/
+ meta?: Meta;
+/**
+* @returns {Stake | undefined}
+*/
+ stake?: Stake;
+/**
+* @returns {number}
+*/
+ state: number;
+}
diff --git a/explorer/wasm/pkg/solana_sdk_wasm.js b/explorer/wasm/pkg/solana_sdk_wasm.js
new file mode 100644
index 0000000000..b51a09e8e7
--- /dev/null
+++ b/explorer/wasm/pkg/solana_sdk_wasm.js
@@ -0,0 +1,2 @@
+import * as wasm from "./solana_sdk_wasm_bg.wasm";
+export * from "./solana_sdk_wasm_bg.js";
\ No newline at end of file
diff --git a/explorer/wasm/pkg/solana_sdk_wasm_bg.d.ts b/explorer/wasm/pkg/solana_sdk_wasm_bg.d.ts
new file mode 100644
index 0000000000..32ac915c54
--- /dev/null
+++ b/explorer/wasm/pkg/solana_sdk_wasm_bg.d.ts
@@ -0,0 +1,44 @@
+/* tslint:disable */
+/* eslint-disable */
+export const memory: WebAssembly.Memory;
+export function __wbg_stakeaccount_free(a: number): void;
+export function __wbg_get_stakeaccount_meta(a: number): number;
+export function __wbg_set_stakeaccount_meta(a: number, b: number): void;
+export function __wbg_get_stakeaccount_stake(a: number): number;
+export function __wbg_set_stakeaccount_stake(a: number, b: number): void;
+export function __wbg_get_stakeaccount_state(a: number): number;
+export function __wbg_set_stakeaccount_state(a: number, b: number): void;
+export function stakeaccount_fromAccountData(a: number, b: number): number;
+export function stakeaccount_displayState(a: number, b: number): void;
+export function __wbg_lockup_free(a: number): void;
+export function __wbg_get_lockup_custodian(a: number): number;
+export function __wbg_set_lockup_custodian(a: number, b: number): void;
+export function lockup_unix_timestamp(a: number): number;
+export function lockup_epoch(a: number): number;
+export function __wbg_pubkey_free(a: number): void;
+export function pubkey_toBase58(a: number, b: number): void;
+export function __wbg_authorized_free(a: number): void;
+export function __wbg_get_authorized_staker(a: number): number;
+export function __wbg_set_authorized_staker(a: number, b: number): void;
+export function __wbg_get_authorized_withdrawer(a: number): number;
+export function __wbg_set_authorized_withdrawer(a: number, b: number): void;
+export function __wbg_meta_free(a: number): void;
+export function __wbg_get_meta_authorized(a: number): number;
+export function __wbg_set_meta_authorized(a: number, b: number): void;
+export function __wbg_get_meta_lockup(a: number): number;
+export function __wbg_set_meta_lockup(a: number, b: number): void;
+export function meta_rent_exempt_reserve(a: number): number;
+export function __wbg_stake_free(a: number): void;
+export function __wbg_get_stake_delegation(a: number): number;
+export function __wbg_set_stake_delegation(a: number, b: number): void;
+export function stake_credits_observed(a: number): number;
+export function __wbg_delegation_free(a: number): void;
+export function delegation_voter_pubkey(a: number): number;
+export function delegation_stake(a: number): number;
+export function delegation_isBootstrapStake(a: number): number;
+export function delegation_isDeactivated(a: number): number;
+export function delegation_activation_epoch(a: number): number;
+export function delegation_deactivation_epoch(a: number): number;
+export function delegation_warmup_cooldown_rate(a: number): number;
+export function __wbindgen_malloc(a: number): number;
+export function __wbindgen_free(a: number, b: number): void;
diff --git a/explorer/wasm/pkg/solana_sdk_wasm_bg.js b/explorer/wasm/pkg/solana_sdk_wasm_bg.js
new file mode 100644
index 0000000000..2fb23b7893
--- /dev/null
+++ b/explorer/wasm/pkg/solana_sdk_wasm_bg.js
@@ -0,0 +1,483 @@
+import * as wasm from './solana_sdk_wasm_bg.wasm';
+
+const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;
+
+let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });
+
+cachedTextDecoder.decode();
+
+let cachegetUint8Memory0 = null;
+function getUint8Memory0() {
+ if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
+ cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
+ }
+ return cachegetUint8Memory0;
+}
+
+function getStringFromWasm0(ptr, len) {
+ return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
+}
+
+const heap = new Array(32).fill(undefined);
+
+heap.push(undefined, null, true, false);
+
+let heap_next = heap.length;
+
+function addHeapObject(obj) {
+ if (heap_next === heap.length) heap.push(heap.length + 1);
+ const idx = heap_next;
+ heap_next = heap[idx];
+
+ heap[idx] = obj;
+ return idx;
+}
+
+function getObject(idx) { return heap[idx]; }
+
+function dropObject(idx) {
+ if (idx < 36) return;
+ heap[idx] = heap_next;
+ heap_next = idx;
+}
+
+function takeObject(idx) {
+ const ret = getObject(idx);
+ dropObject(idx);
+ return ret;
+}
+
+function isLikeNone(x) {
+ return x === undefined || x === null;
+}
+
+function _assertClass(instance, klass) {
+ if (!(instance instanceof klass)) {
+ throw new Error(`expected instance of ${klass.name}`);
+ }
+ return instance.ptr;
+}
+
+let WASM_VECTOR_LEN = 0;
+
+function passArray8ToWasm0(arg, malloc) {
+ const ptr = malloc(arg.length * 1);
+ getUint8Memory0().set(arg, ptr / 1);
+ WASM_VECTOR_LEN = arg.length;
+ return ptr;
+}
+
+let cachegetInt32Memory0 = null;
+function getInt32Memory0() {
+ if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
+ cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
+ }
+ return cachegetInt32Memory0;
+}
+/**
+*/
+export const StakeState = Object.freeze({ Uninitialized:0,Initialized:1,Delegated:2,RewardsPool:3, });
+/**
+*/
+export class Authorized {
+
+ static __wrap(ptr) {
+ const obj = Object.create(Authorized.prototype);
+ obj.ptr = ptr;
+
+ return obj;
+ }
+
+ free() {
+ const ptr = this.ptr;
+ this.ptr = 0;
+
+ wasm.__wbg_authorized_free(ptr);
+ }
+ /**
+ * @returns {Pubkey}
+ */
+ get staker() {
+ var ret = wasm.__wbg_get_authorized_staker(this.ptr);
+ return Pubkey.__wrap(ret);
+ }
+ /**
+ * @param {Pubkey} arg0
+ */
+ set staker(arg0) {
+ _assertClass(arg0, Pubkey);
+ var ptr0 = arg0.ptr;
+ arg0.ptr = 0;
+ wasm.__wbg_set_authorized_staker(this.ptr, ptr0);
+ }
+ /**
+ * @returns {Pubkey}
+ */
+ get withdrawer() {
+ var ret = wasm.__wbg_get_authorized_withdrawer(this.ptr);
+ return Pubkey.__wrap(ret);
+ }
+ /**
+ * @param {Pubkey} arg0
+ */
+ set withdrawer(arg0) {
+ _assertClass(arg0, Pubkey);
+ var ptr0 = arg0.ptr;
+ arg0.ptr = 0;
+ wasm.__wbg_set_authorized_withdrawer(this.ptr, ptr0);
+ }
+}
+/**
+*/
+export class Delegation {
+
+ static __wrap(ptr) {
+ const obj = Object.create(Delegation.prototype);
+ obj.ptr = ptr;
+
+ return obj;
+ }
+
+ free() {
+ const ptr = this.ptr;
+ this.ptr = 0;
+
+ wasm.__wbg_delegation_free(ptr);
+ }
+ /**
+ * @returns {Pubkey}
+ */
+ get voterPubkey() {
+ var ret = wasm.delegation_voter_pubkey(this.ptr);
+ return Pubkey.__wrap(ret);
+ }
+ /**
+ * @returns {number}
+ */
+ get stake() {
+ var ret = wasm.delegation_stake(this.ptr);
+ return ret;
+ }
+ /**
+ * @returns {boolean}
+ */
+ isBootstrapStake() {
+ var ret = wasm.delegation_isBootstrapStake(this.ptr);
+ return ret !== 0;
+ }
+ /**
+ * @returns {boolean}
+ */
+ isDeactivated() {
+ var ret = wasm.delegation_isDeactivated(this.ptr);
+ return ret !== 0;
+ }
+ /**
+ * @returns {number}
+ */
+ get activationEpoch() {
+ var ret = wasm.delegation_activation_epoch(this.ptr);
+ return ret;
+ }
+ /**
+ * @returns {number}
+ */
+ get deactivationEpoch() {
+ var ret = wasm.delegation_deactivation_epoch(this.ptr);
+ return ret;
+ }
+ /**
+ * @returns {number}
+ */
+ get warmupCooldownRate() {
+ var ret = wasm.delegation_warmup_cooldown_rate(this.ptr);
+ return ret;
+ }
+}
+/**
+*/
+export class Lockup {
+
+ static __wrap(ptr) {
+ const obj = Object.create(Lockup.prototype);
+ obj.ptr = ptr;
+
+ return obj;
+ }
+
+ free() {
+ const ptr = this.ptr;
+ this.ptr = 0;
+
+ wasm.__wbg_lockup_free(ptr);
+ }
+ /**
+ * custodian signature on a transaction exempts the operation from
+ * lockup constraints
+ * @returns {Pubkey}
+ */
+ get custodian() {
+ var ret = wasm.__wbg_get_lockup_custodian(this.ptr);
+ return Pubkey.__wrap(ret);
+ }
+ /**
+ * custodian signature on a transaction exempts the operation from
+ * lockup constraints
+ * @param {Pubkey} arg0
+ */
+ set custodian(arg0) {
+ _assertClass(arg0, Pubkey);
+ var ptr0 = arg0.ptr;
+ arg0.ptr = 0;
+ wasm.__wbg_set_lockup_custodian(this.ptr, ptr0);
+ }
+ /**
+ * @returns {number}
+ */
+ get unixTimestamp() {
+ var ret = wasm.lockup_unix_timestamp(this.ptr);
+ return ret;
+ }
+ /**
+ * @returns {number}
+ */
+ get epoch() {
+ var ret = wasm.lockup_epoch(this.ptr);
+ return ret;
+ }
+}
+/**
+*/
+export class Meta {
+
+ static __wrap(ptr) {
+ const obj = Object.create(Meta.prototype);
+ obj.ptr = ptr;
+
+ return obj;
+ }
+
+ free() {
+ const ptr = this.ptr;
+ this.ptr = 0;
+
+ wasm.__wbg_meta_free(ptr);
+ }
+ /**
+ * @returns {Authorized}
+ */
+ get authorized() {
+ var ret = wasm.__wbg_get_meta_authorized(this.ptr);
+ return Authorized.__wrap(ret);
+ }
+ /**
+ * @param {Authorized} arg0
+ */
+ set authorized(arg0) {
+ _assertClass(arg0, Authorized);
+ var ptr0 = arg0.ptr;
+ arg0.ptr = 0;
+ wasm.__wbg_set_meta_authorized(this.ptr, ptr0);
+ }
+ /**
+ * @returns {Lockup}
+ */
+ get lockup() {
+ var ret = wasm.__wbg_get_meta_lockup(this.ptr);
+ return Lockup.__wrap(ret);
+ }
+ /**
+ * @param {Lockup} arg0
+ */
+ set lockup(arg0) {
+ _assertClass(arg0, Lockup);
+ var ptr0 = arg0.ptr;
+ arg0.ptr = 0;
+ wasm.__wbg_set_meta_lockup(this.ptr, ptr0);
+ }
+ /**
+ * @returns {number}
+ */
+ get rentExemptReserve() {
+ var ret = wasm.meta_rent_exempt_reserve(this.ptr);
+ return ret;
+ }
+}
+/**
+*/
+export class Pubkey {
+
+ static __wrap(ptr) {
+ const obj = Object.create(Pubkey.prototype);
+ obj.ptr = ptr;
+
+ return obj;
+ }
+
+ free() {
+ const ptr = this.ptr;
+ this.ptr = 0;
+
+ wasm.__wbg_pubkey_free(ptr);
+ }
+ /**
+ * @returns {string}
+ */
+ toBase58() {
+ try {
+ wasm.pubkey_toBase58(8, this.ptr);
+ var r0 = getInt32Memory0()[8 / 4 + 0];
+ var r1 = getInt32Memory0()[8 / 4 + 1];
+ return getStringFromWasm0(r0, r1);
+ } finally {
+ wasm.__wbindgen_free(r0, r1);
+ }
+ }
+}
+/**
+*/
+export class Stake {
+
+ static __wrap(ptr) {
+ const obj = Object.create(Stake.prototype);
+ obj.ptr = ptr;
+
+ return obj;
+ }
+
+ free() {
+ const ptr = this.ptr;
+ this.ptr = 0;
+
+ wasm.__wbg_stake_free(ptr);
+ }
+ /**
+ * @returns {Delegation}
+ */
+ get delegation() {
+ var ret = wasm.__wbg_get_stake_delegation(this.ptr);
+ return Delegation.__wrap(ret);
+ }
+ /**
+ * @param {Delegation} arg0
+ */
+ set delegation(arg0) {
+ _assertClass(arg0, Delegation);
+ var ptr0 = arg0.ptr;
+ arg0.ptr = 0;
+ wasm.__wbg_set_stake_delegation(this.ptr, ptr0);
+ }
+ /**
+ * @returns {number}
+ */
+ get creditsObserved() {
+ var ret = wasm.stake_credits_observed(this.ptr);
+ return ret;
+ }
+}
+/**
+*/
+export class StakeAccount {
+
+ static __wrap(ptr) {
+ const obj = Object.create(StakeAccount.prototype);
+ obj.ptr = ptr;
+
+ return obj;
+ }
+
+ free() {
+ const ptr = this.ptr;
+ this.ptr = 0;
+
+ wasm.__wbg_stakeaccount_free(ptr);
+ }
+ /**
+ * @returns {Meta | undefined}
+ */
+ get meta() {
+ var ret = wasm.__wbg_get_stakeaccount_meta(this.ptr);
+ return ret === 0 ? undefined : Meta.__wrap(ret);
+ }
+ /**
+ * @param {Meta | undefined} arg0
+ */
+ set meta(arg0) {
+ let ptr0 = 0;
+ if (!isLikeNone(arg0)) {
+ _assertClass(arg0, Meta);
+ ptr0 = arg0.ptr;
+ arg0.ptr = 0;
+ }
+ wasm.__wbg_set_stakeaccount_meta(this.ptr, ptr0);
+ }
+ /**
+ * @returns {Stake | undefined}
+ */
+ get stake() {
+ var ret = wasm.__wbg_get_stakeaccount_stake(this.ptr);
+ return ret === 0 ? undefined : Stake.__wrap(ret);
+ }
+ /**
+ * @param {Stake | undefined} arg0
+ */
+ set stake(arg0) {
+ let ptr0 = 0;
+ if (!isLikeNone(arg0)) {
+ _assertClass(arg0, Stake);
+ ptr0 = arg0.ptr;
+ arg0.ptr = 0;
+ }
+ wasm.__wbg_set_stakeaccount_stake(this.ptr, ptr0);
+ }
+ /**
+ * @returns {number}
+ */
+ get state() {
+ var ret = wasm.__wbg_get_stakeaccount_state(this.ptr);
+ return ret >>> 0;
+ }
+ /**
+ * @param {number} arg0
+ */
+ set state(arg0) {
+ wasm.__wbg_set_stakeaccount_state(this.ptr, arg0);
+ }
+ /**
+ * @param {Uint8Array} data
+ * @returns {StakeAccount}
+ */
+ static fromAccountData(data) {
+ var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
+ var len0 = WASM_VECTOR_LEN;
+ var ret = wasm.stakeaccount_fromAccountData(ptr0, len0);
+ return StakeAccount.__wrap(ret);
+ }
+ /**
+ * @returns {string}
+ */
+ displayState() {
+ try {
+ wasm.stakeaccount_displayState(8, this.ptr);
+ var r0 = getInt32Memory0()[8 / 4 + 0];
+ var r1 = getInt32Memory0()[8 / 4 + 1];
+ return getStringFromWasm0(r0, r1);
+ } finally {
+ wasm.__wbindgen_free(r0, r1);
+ }
+ }
+}
+
+export const __wbindgen_string_new = function(arg0, arg1) {
+ var ret = getStringFromWasm0(arg0, arg1);
+ return addHeapObject(ret);
+};
+
+export const __wbindgen_throw = function(arg0, arg1) {
+ throw new Error(getStringFromWasm0(arg0, arg1));
+};
+
+export const __wbindgen_rethrow = function(arg0) {
+ throw takeObject(arg0);
+};
+
diff --git a/explorer/wasm/pkg/solana_sdk_wasm_bg.wasm b/explorer/wasm/pkg/solana_sdk_wasm_bg.wasm
new file mode 100644
index 0000000000..588775629c
Binary files /dev/null and b/explorer/wasm/pkg/solana_sdk_wasm_bg.wasm differ
diff --git a/explorer/wasm/src/lib.rs b/explorer/wasm/src/lib.rs
new file mode 100644
index 0000000000..9363333a88
--- /dev/null
+++ b/explorer/wasm/src/lib.rs
@@ -0,0 +1,3 @@
+mod stake_account;
+
+pub use stake_account::*;
diff --git a/explorer/wasm/src/stake_account.rs b/explorer/wasm/src/stake_account.rs
new file mode 100644
index 0000000000..93a0509643
--- /dev/null
+++ b/explorer/wasm/src/stake_account.rs
@@ -0,0 +1,217 @@
+use serde::{Deserialize, Serialize};
+use wasm_bindgen::prelude::*;
+
+#[derive(Serialize, Deserialize, PartialEq, Clone, Copy)]
+#[allow(clippy::large_enum_variant)]
+pub enum StakeState {
+ Uninitialized,
+ Initialized(Meta),
+ Stake(Meta, Stake),
+ RewardsPool,
+}
+
+#[wasm_bindgen(js_name = StakeState)]
+#[derive(Copy, Clone)]
+pub enum State {
+ Uninitialized,
+ Initialized,
+ Delegated,
+ RewardsPool,
+}
+
+#[wasm_bindgen]
+pub struct StakeAccount {
+ pub meta: Option,
+ pub stake: Option,
+ pub state: State,
+}
+
+impl From for StakeAccount {
+ fn from(state: StakeState) -> Self {
+ match state {
+ StakeState::Uninitialized => StakeAccount {
+ state: State::Uninitialized,
+ meta: None,
+ stake: None,
+ },
+ StakeState::Initialized(meta) => StakeAccount {
+ state: State::Initialized,
+ meta: Some(meta),
+ stake: None,
+ },
+ StakeState::Stake(meta, stake) => StakeAccount {
+ state: State::Delegated,
+ meta: Some(meta),
+ stake: Some(stake),
+ },
+ StakeState::RewardsPool => StakeAccount {
+ state: State::RewardsPool,
+ meta: None,
+ stake: None,
+ },
+ }
+ }
+}
+
+#[wasm_bindgen]
+impl StakeAccount {
+ #[wasm_bindgen(js_name = fromAccountData)]
+ pub fn from_account_data(data: &[u8]) -> Result {
+ let stake_state: StakeState = bincode::deserialize(data)
+ .map_err(|_| JsValue::from_str("invalid stake account data"))?;
+ return Ok(stake_state.into());
+ }
+
+ #[wasm_bindgen(js_name = displayState)]
+ pub fn display_state(&self) -> String {
+ match self.state {
+ State::Uninitialized => "Uninitialized".to_string(),
+ State::Initialized => "Initialized".to_string(),
+ State::Delegated => "Delegated".to_string(),
+ State::RewardsPool => "RewardsPool".to_string(),
+ }
+ }
+}
+
+/// UnixTimestamp is an approximate measure of real-world time,
+/// expressed as Unix time (ie. seconds since the Unix epoch)
+pub type UnixTimestamp = i64;
+
+#[wasm_bindgen]
+#[derive(Serialize, Deserialize, PartialEq, Clone, Copy)]
+pub struct Lockup {
+ /// UnixTimestamp at which this stake will allow withdrawal, or
+ /// changes to authorized staker or withdrawer, unless the
+ /// transaction is signed by the custodian
+ unix_timestamp: UnixTimestamp,
+ /// epoch height at which this stake will allow withdrawal, or
+ /// changes to authorized staker or withdrawer, unless the
+ /// transaction is signed by the custodian
+ /// to the custodian
+ epoch: Epoch,
+ /// custodian signature on a transaction exempts the operation from
+ /// lockup constraints
+ pub custodian: Pubkey,
+}
+
+#[wasm_bindgen]
+impl Lockup {
+ #[wasm_bindgen(getter = unixTimestamp)]
+ pub fn unix_timestamp(&self) -> f64 {
+ self.unix_timestamp as f64
+ }
+
+ #[wasm_bindgen(getter)]
+ pub fn epoch(&self) -> f64 {
+ self.epoch as f64
+ }
+}
+
+/// Epoch is a unit of time a given leader schedule is honored,
+/// some number of Slots.
+pub type Epoch = u64;
+
+#[wasm_bindgen]
+#[repr(transparent)]
+#[derive(Serialize, Deserialize, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct Pubkey([u8; 32]);
+
+#[wasm_bindgen]
+impl Pubkey {
+ #[wasm_bindgen(js_name = toBase58)]
+ pub fn to_base_58(&self) -> String {
+ bs58::encode(&self.0).into_string()
+ }
+}
+
+#[wasm_bindgen]
+#[derive(Serialize, Deserialize, PartialEq, Clone, Copy)]
+pub struct Authorized {
+ pub staker: Pubkey,
+ pub withdrawer: Pubkey,
+}
+
+#[wasm_bindgen]
+#[derive(Serialize, Deserialize, PartialEq, Clone, Copy)]
+pub struct Meta {
+ rent_exempt_reserve: u64,
+ pub authorized: Authorized,
+ pub lockup: Lockup,
+}
+
+#[wasm_bindgen]
+impl Meta {
+ #[wasm_bindgen(getter = rentExemptReserve)]
+ pub fn rent_exempt_reserve(&self) -> f64 {
+ self.rent_exempt_reserve as f64
+ }
+}
+
+#[wasm_bindgen]
+#[derive(Serialize, Deserialize, PartialEq, Clone, Copy)]
+pub struct Stake {
+ pub delegation: Delegation,
+ /// credits observed is credits from vote account state when delegated or redeemed
+ credits_observed: u64,
+}
+
+#[wasm_bindgen]
+impl Stake {
+ #[wasm_bindgen(getter = creditsObserved)]
+ pub fn credits_observed(&self) -> f64 {
+ self.credits_observed as f64
+ }
+}
+
+#[wasm_bindgen]
+#[derive(Serialize, Deserialize, PartialEq, Clone, Copy)]
+pub struct Delegation {
+ /// to whom the stake is delegated
+ voter_pubkey: Pubkey,
+ /// activated stake amount, set at delegate() time
+ stake: u64,
+ /// epoch at which this stake was activated, std::Epoch::MAX if is a bootstrap stake
+ activation_epoch: Epoch,
+ /// epoch the stake was deactivated, std::Epoch::MAX if not deactivated
+ deactivation_epoch: Epoch,
+ /// how much stake we can activate per-epoch as a fraction of currently effective stake
+ warmup_cooldown_rate: f64,
+}
+
+#[wasm_bindgen]
+impl Delegation {
+ #[wasm_bindgen(getter = voterPubkey)]
+ pub fn voter_pubkey(&self) -> Pubkey {
+ self.voter_pubkey
+ }
+
+ #[wasm_bindgen(getter)]
+ pub fn stake(&self) -> f64 {
+ self.stake as f64
+ }
+
+ #[wasm_bindgen(js_name = isBootstrapStake)]
+ pub fn is_bootstrap_stake(&self) -> bool {
+ self.activation_epoch == Epoch::MAX
+ }
+
+ #[wasm_bindgen(js_name = isDeactivated)]
+ pub fn is_deactivated(&self) -> bool {
+ self.deactivation_epoch != Epoch::MAX
+ }
+
+ #[wasm_bindgen(getter = activationEpoch)]
+ pub fn activation_epoch(&self) -> f64 {
+ self.activation_epoch as f64
+ }
+
+ #[wasm_bindgen(getter = deactivationEpoch)]
+ pub fn deactivation_epoch(&self) -> f64 {
+ self.deactivation_epoch as f64
+ }
+
+ #[wasm_bindgen(getter = warmupCooldownRate)]
+ pub fn warmup_cooldown_rate(&self) -> f64 {
+ self.warmup_cooldown_rate
+ }
+}