2021-06-21 16:53:06 -07:00
|
|
|
import React from "react";
|
|
|
|
import { PublicKey, SystemProgram } from "@solana/web3.js";
|
|
|
|
import { Address } from "components/common/Address";
|
|
|
|
import {
|
|
|
|
Account,
|
|
|
|
useAccountInfo,
|
2022-09-24 00:10:14 -07:00
|
|
|
useAddressLookupTable,
|
2021-06-21 16:53:06 -07:00
|
|
|
useFetchAccountInfo,
|
|
|
|
} from "providers/accounts";
|
|
|
|
import { ClusterStatus, useCluster } from "providers/cluster";
|
|
|
|
import { addressLabel } from "utils/tx";
|
|
|
|
import { lamportsToSolString } from "utils";
|
|
|
|
|
|
|
|
type AccountValidator = (account: Account) => string | undefined;
|
|
|
|
|
|
|
|
export const createFeePayerValidator = (
|
|
|
|
feeLamports: number
|
|
|
|
): AccountValidator => {
|
|
|
|
return (account: Account): string | undefined => {
|
2022-10-13 23:41:32 -07:00
|
|
|
if (account.lamports === 0) return "Account doesn't exist";
|
|
|
|
if (!account.owner.equals(SystemProgram.programId))
|
2021-06-21 16:53:06 -07:00
|
|
|
return "Only system-owned accounts can pay fees";
|
|
|
|
if (account.lamports < feeLamports) {
|
|
|
|
return "Insufficient funds for fees";
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export const programValidator = (account: Account): string | undefined => {
|
2022-10-13 23:41:32 -07:00
|
|
|
if (account.lamports === 0) return "Account doesn't exist";
|
|
|
|
if (!account.executable) return "Only executable accounts can be invoked";
|
2021-06-21 16:53:06 -07:00
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2022-09-24 00:10:14 -07:00
|
|
|
export function AddressFromLookupTableWithContext({
|
|
|
|
lookupTableKey,
|
|
|
|
lookupTableIndex,
|
|
|
|
}: {
|
|
|
|
lookupTableKey: PublicKey;
|
|
|
|
lookupTableIndex: number;
|
|
|
|
}) {
|
2022-10-16 06:18:49 -07:00
|
|
|
const lookupTableInfo = useAddressLookupTable(lookupTableKey.toBase58());
|
|
|
|
const lookupTable = lookupTableInfo && lookupTableInfo[0];
|
2022-09-24 00:10:14 -07:00
|
|
|
if (!lookupTable) {
|
|
|
|
return (
|
|
|
|
<span className="text-muted">
|
|
|
|
<span className="spinner-grow spinner-grow-sm me-2"></span>
|
|
|
|
Loading
|
|
|
|
</span>
|
|
|
|
);
|
|
|
|
} else if (typeof lookupTable === "string") {
|
|
|
|
return <div>Invalid Lookup Table</div>;
|
2022-10-16 06:18:49 -07:00
|
|
|
} else if (lookupTableIndex >= lookupTable.state.addresses.length) {
|
2022-09-24 00:10:14 -07:00
|
|
|
return <div>Invalid Lookup Table Index</div>;
|
2022-10-16 06:18:49 -07:00
|
|
|
} else {
|
|
|
|
const pubkey = lookupTable.state.addresses[lookupTableIndex];
|
|
|
|
return (
|
|
|
|
<div className="d-flex align-items-end flex-column">
|
|
|
|
<Address pubkey={pubkey} link />
|
|
|
|
<AccountInfo pubkey={pubkey} />
|
|
|
|
</div>
|
|
|
|
);
|
2022-09-24 00:10:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-21 16:53:06 -07:00
|
|
|
export function AddressWithContext({
|
|
|
|
pubkey,
|
|
|
|
validator,
|
|
|
|
}: {
|
|
|
|
pubkey: PublicKey;
|
|
|
|
validator?: AccountValidator;
|
|
|
|
}) {
|
|
|
|
return (
|
|
|
|
<div className="d-flex align-items-end flex-column">
|
|
|
|
<Address pubkey={pubkey} link />
|
|
|
|
<AccountInfo pubkey={pubkey} validator={validator} />
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function AccountInfo({
|
|
|
|
pubkey,
|
|
|
|
validator,
|
|
|
|
}: {
|
|
|
|
pubkey: PublicKey;
|
|
|
|
validator?: AccountValidator;
|
|
|
|
}) {
|
|
|
|
const address = pubkey.toBase58();
|
|
|
|
const fetchAccount = useFetchAccountInfo();
|
|
|
|
const info = useAccountInfo(address);
|
|
|
|
const { cluster, status } = useCluster();
|
|
|
|
|
|
|
|
// Fetch account on load
|
|
|
|
React.useEffect(() => {
|
|
|
|
if (!info && status === ClusterStatus.Connected && pubkey) {
|
2022-10-16 06:18:49 -07:00
|
|
|
fetchAccount(pubkey, "skip");
|
2021-06-21 16:53:06 -07:00
|
|
|
}
|
|
|
|
}, [address, status]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
|
2022-10-13 23:41:32 -07:00
|
|
|
const account = info?.data;
|
|
|
|
if (!account)
|
2021-06-21 16:53:06 -07:00
|
|
|
return (
|
|
|
|
<span className="text-muted">
|
2021-11-28 12:49:22 -08:00
|
|
|
<span className="spinner-grow spinner-grow-sm me-2"></span>
|
2021-06-21 16:53:06 -07:00
|
|
|
Loading
|
|
|
|
</span>
|
|
|
|
);
|
|
|
|
|
2022-10-13 23:41:32 -07:00
|
|
|
const errorMessage = validator && validator(account);
|
2021-06-21 16:53:06 -07:00
|
|
|
if (errorMessage) return <span className="text-warning">{errorMessage}</span>;
|
|
|
|
|
2022-10-13 23:41:32 -07:00
|
|
|
if (account.lamports === 0) {
|
2022-06-24 03:40:30 -07:00
|
|
|
return <span className="text-muted">Account doesn't exist</span>;
|
2021-06-21 16:53:06 -07:00
|
|
|
}
|
|
|
|
|
2022-10-13 23:41:32 -07:00
|
|
|
const ownerAddress = account.owner.toBase58();
|
2022-06-24 03:40:30 -07:00
|
|
|
const ownerLabel = addressLabel(ownerAddress, cluster);
|
2021-06-21 16:53:06 -07:00
|
|
|
|
|
|
|
return (
|
|
|
|
<span className="text-muted">
|
2022-06-24 03:40:30 -07:00
|
|
|
{`Owned by ${ownerLabel || ownerAddress}.`}
|
2022-10-13 23:41:32 -07:00
|
|
|
{` Balance is ${lamportsToSolString(account.lamports)} SOL.`}
|
2022-10-16 06:18:49 -07:00
|
|
|
{account.space !== undefined &&
|
|
|
|
` Size is ${new Intl.NumberFormat("en-US").format(
|
|
|
|
account.space
|
|
|
|
)} byte(s).`}
|
2021-06-21 16:53:06 -07:00
|
|
|
</span>
|
|
|
|
);
|
|
|
|
}
|