Add verified/unverified badge to Program Account view (#22825)
* Add verified/unverified badge to Program Account view * Generalize to any number of build verification providers
This commit is contained in:
parent
d2c89213ff
commit
86c3990c25
|
@ -15,6 +15,9 @@ import { useCluster } from "providers/cluster";
|
|||
import { ErrorCard } from "components/common/ErrorCard";
|
||||
import { UnknownAccountCard } from "components/account/UnknownAccountCard";
|
||||
import { Downloadable } from "components/common/Downloadable";
|
||||
import { CheckingBadge, VerifiedBadge } from "components/common/VerifiedBadge";
|
||||
import { InfoTooltip } from "components/common/InfoTooltip";
|
||||
import { useVerifiableBuilds } from "utils/program-verification";
|
||||
|
||||
export function UpgradeableLoaderAccountSection({
|
||||
account,
|
||||
|
@ -72,6 +75,7 @@ export function UpgradeableProgramSection({
|
|||
const refresh = useFetchAccountInfo();
|
||||
const { cluster } = useCluster();
|
||||
const label = addressLabel(account.pubkey.toBase58(), cluster);
|
||||
const { loading, verifiableBuilds } = useVerifiableBuilds(account.pubkey);
|
||||
return (
|
||||
<div className="card">
|
||||
<div className="card-header">
|
||||
|
@ -122,6 +126,22 @@ export function UpgradeableProgramSection({
|
|||
{programData.authority !== null ? "Yes" : "No"}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<LastVerifiedBuildLabel />
|
||||
</td>
|
||||
<td className="text-lg-end">
|
||||
{loading ? (
|
||||
<CheckingBadge />
|
||||
) : (
|
||||
<>
|
||||
{verifiableBuilds.map((b) => (
|
||||
<VerifiedBadge verifiableBuild={b} />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last Deployed Slot</td>
|
||||
<td className="text-lg-end">
|
||||
|
@ -141,6 +161,14 @@ export function UpgradeableProgramSection({
|
|||
);
|
||||
}
|
||||
|
||||
function LastVerifiedBuildLabel() {
|
||||
return (
|
||||
<InfoTooltip text="Indicates whether the program currently deployed on-chain is verified to match the associated published source code, when it is available.">
|
||||
Verifiable Build Status
|
||||
</InfoTooltip>
|
||||
);
|
||||
}
|
||||
|
||||
export function UpgradeableProgramDataSection({
|
||||
account,
|
||||
programData,
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import { VerifiableBuild } from "utils/program-verification";
|
||||
|
||||
export function VerifiedBadge({
|
||||
verifiableBuild,
|
||||
}: {
|
||||
verifiableBuild: VerifiableBuild;
|
||||
}) {
|
||||
if (verifiableBuild && verifiableBuild.verified_slot) {
|
||||
return (
|
||||
<h3 className="mb-0">
|
||||
<a
|
||||
className="c-pointer badge bg-success-soft rank"
|
||||
href={verifiableBuild.url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{verifiableBuild.label}: Verified
|
||||
</a>
|
||||
</h3>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<h3 className="mb-0">
|
||||
<span className="badge bg-warning-soft rank">
|
||||
{verifiableBuild.label}: Unverified
|
||||
</span>
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function CheckingBadge() {
|
||||
return (
|
||||
<h3 className="mb-0">
|
||||
<span className="badge bg-dark rank">Checking</span>
|
||||
</h3>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
import { PublicKey } from "@solana/web3.js";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export type VerifiableBuild =
|
||||
| {
|
||||
label: string;
|
||||
id: number;
|
||||
verified_slot: number;
|
||||
url: string;
|
||||
}
|
||||
| {
|
||||
label: string;
|
||||
verified_slot: null;
|
||||
};
|
||||
|
||||
export function useVerifiableBuilds(programAddress: PublicKey) {
|
||||
const { loading: loadingAnchor, verifiableBuild: verifiedBuildAnchor } =
|
||||
useAnchorVerifiableBuild(programAddress);
|
||||
|
||||
return {
|
||||
loading: loadingAnchor,
|
||||
verifiableBuilds: [verifiedBuildAnchor],
|
||||
};
|
||||
}
|
||||
|
||||
// ANCHOR
|
||||
|
||||
const defaultAnchorBuild = {
|
||||
label: "Anchor",
|
||||
verified_slot: null,
|
||||
};
|
||||
|
||||
export function useAnchorVerifiableBuild(programAddress: PublicKey) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [verifiableBuild, setVerifiableBuild] =
|
||||
useState<VerifiableBuild>(defaultAnchorBuild);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getAnchorVerifiableBuild(programAddress)
|
||||
.then(setVerifiableBuild)
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setVerifiableBuild(defaultAnchorBuild);
|
||||
})
|
||||
.finally(() => setLoading(false));
|
||||
}, [programAddress, setVerifiableBuild, setLoading]);
|
||||
|
||||
return {
|
||||
loading,
|
||||
verifiableBuild,
|
||||
};
|
||||
}
|
||||
|
||||
export interface AnchorBuild {
|
||||
aborted: boolean;
|
||||
address: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
descriptor: string[];
|
||||
docker: string;
|
||||
id: number;
|
||||
name: string;
|
||||
sha256: string;
|
||||
upgrade_authority: string;
|
||||
verified: string;
|
||||
verified_slot: number;
|
||||
state: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a verified build from the anchor registry. null if no such
|
||||
* verified build exists, e.g., if the program has been upgraded since the
|
||||
* last verified build.
|
||||
*/
|
||||
export async function getAnchorVerifiableBuild(
|
||||
programId: PublicKey,
|
||||
limit: number = 5
|
||||
): Promise<VerifiableBuild> {
|
||||
const url = `https://anchor.projectserum.com/api/v0/program/${programId.toString()}/latest?limit=${limit}`;
|
||||
const latestBuildsResp = await fetch(url);
|
||||
|
||||
// Filter out all non successful builds.
|
||||
const latestBuilds = (await latestBuildsResp.json()).filter(
|
||||
(b: AnchorBuild) =>
|
||||
!b.aborted && b.state === "Built" && b.verified === "Verified"
|
||||
) as AnchorBuild[];
|
||||
|
||||
if (latestBuilds.length === 0) {
|
||||
return defaultAnchorBuild;
|
||||
}
|
||||
|
||||
// Get the latest build.
|
||||
const { verified_slot, id } = latestBuilds[0];
|
||||
return {
|
||||
...defaultAnchorBuild,
|
||||
verified_slot,
|
||||
id,
|
||||
url: `https://anchor.projectserum.com/build/${id}`,
|
||||
};
|
||||
}
|
||||
|
||||
// END ANCHOR
|
Loading…
Reference in New Issue