Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions app/address/[address]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,20 @@ function AddressLayoutInner({ children, params: { address } }: InnerProps) {

return (
<PageContainer variant="pulled-up">
<Header
address={address}
account={info?.data}
tokenInfo={fullTokenInfo}
isTokenInfoLoading={isTokenInfoLoading}
/>
{/* Content is capped to a centered `col` (960px) column inside the fluid PageContainer;
the sticky tab bar (see MoreSection) spans full width but keeps its border col-width. */}
<div className="mx-auto w-full max-w-col">
<Header
address={address}
account={info?.data}
tokenInfo={fullTokenInfo}
isTokenInfoLoading={isTokenInfoLoading}
/>
</div>
{!pubkey ? (
<ErrorCard text={`Address "${address}" is not valid`} />
<div className="mx-auto w-full max-w-col">
<ErrorCard text={`Address "${address}" is not valid`} />
</div>
) : (
<DetailsSections
info={info}
Expand Down Expand Up @@ -280,7 +286,9 @@ function DetailsSections({
return (
<>
{FLAGGED_ACCOUNTS_WARNING[address] ?? null}
<InfoSection account={account} tokenInfo={tokenInfo} />
<div className="mx-auto w-full max-w-col">
<InfoSection account={account} tokenInfo={tokenInfo} />
</div>
{notification}
<MoreSection baseUrl={`/address/${address}`} tabs={navigationTabs} asyncChildren={asyncTabChildren}>
{children}
Expand Down Expand Up @@ -388,14 +396,20 @@ function MoreSection({

return (
<>
<StickyHeader>
{/* Cap the sticky bar (and its bottom border) to the `col` content-column width when
inline, so the border lines up with the Header/InfoSection column. When stuck the
bar goes full-bleed (StickyHeader forces maxWidth:none + 100vw). The inner
PageContainer cancels StickyHeader's gutter offset so the tabs sit on the column. */}
<StickyHeader className="mx-auto w-full max-w-col">
<PageContainer>
<NavigationTabs buildHref={buildHref} tabs={tabs}>
{asyncChildren}
</NavigationTabs>
<div className="mx-auto w-full max-w-col">
<NavigationTabs buildHref={buildHref} tabs={tabs}>
{asyncChildren}
</NavigationTabs>
</div>
</PageContainer>
</StickyHeader>
{children}
<div className="mx-auto w-full max-w-col">{children}</div>
</>
);
}
Expand Down
85 changes: 29 additions & 56 deletions app/components/account/ProgramMultisigCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ import {
useSquadsMultisig,
useSquadsMultisigLookup,
} from '@/app/providers/squadsMultisig';
import { Card, CardHeader, CardTitle } from '@/app/shared/ui/Card';
import { BaseTable } from '@/app/shared/ui/Table';
import { SectionCard } from '@/app/shared/ui/Card/SectionCard';
import { KeyValue, LABEL_WIDTH } from '@/app/shared/ui/key-value';

import { Address } from '../common/Address';
import { LoadingCard } from '../common/LoadingCard';
import { TableCardBody } from '../common/TableCardBody';

export function ProgramMultisigCard({ data }: { data: UpgradeableLoaderAccountData }) {
return (
Expand Down Expand Up @@ -47,59 +46,33 @@ function ProgramMultisigCardInner({ programAuthority }: { programAuthority: Publ
members = squadInfo?.multisig.keys ?? [];
}

const memberCount =
squadInfo?.version === 'v4' ? squadInfo?.multisig.members.length : squadInfo?.multisig.keys.length;

return (
<Card ui="dashkit">
<CardHeader ui="dashkit">
<CardTitle as="h3" ui="dashkit" className="flex items-center">
Upgrade Authority Multisig Information
</CardTitle>
</CardHeader>
<TableCardBody>
<BaseTable.Row>
<BaseTable.Cell>Multisig Program</BaseTable.Cell>
<BaseTable.Cell className="text-right">
{squadMapInfo?.version === 'v4' ? 'Squads V4' : 'Squads V3'}
</BaseTable.Cell>
</BaseTable.Row>
<BaseTable.Row>
<BaseTable.Cell>Multisig Program Id</BaseTable.Cell>
<BaseTable.Cell className="text-right">
<Address
pubkey={
new PublicKey(squadMapInfo?.version === 'v4' ? SQUADS_V4_ADDRESS : SQUADS_V3_ADDRESS)
}
alignRight
link
/>
</BaseTable.Cell>
</BaseTable.Row>
<BaseTable.Row>
<BaseTable.Cell>Multisig Account</BaseTable.Cell>
<BaseTable.Cell className="text-right">
{squadMapInfo?.isSquad ? (
<Address pubkey={new PublicKey(squadMapInfo.multisig)} alignRight link />
) : null}
</BaseTable.Cell>
</BaseTable.Row>
<BaseTable.Row>
<BaseTable.Cell>Multisig Approval Threshold</BaseTable.Cell>
<BaseTable.Cell className="text-right">
{squadInfo?.multisig.threshold}
{' of '}
{squadInfo?.version === 'v4'
? squadInfo?.multisig.members.length
: squadInfo?.multisig.keys.length}
</BaseTable.Cell>
</BaseTable.Row>
{members.map((member, idx) => (
<BaseTable.Row key={idx}>
<BaseTable.Cell>Multisig Member {idx + 1}</BaseTable.Cell>
<BaseTable.Cell className="text-right">
<Address pubkey={member} alignRight link />
</BaseTable.Cell>
</BaseTable.Row>
))}
</TableCardBody>
</Card>
<SectionCard title="Upgrade Authority Multisig Information">
<KeyValue label="Multisig Program" labelWidth={LABEL_WIDTH} row>
{squadMapInfo?.version === 'v4' ? 'Squads V4' : 'Squads V3'}
</KeyValue>
<KeyValue label="Multisig Program Id" labelWidth={LABEL_WIDTH} row>
<Address
pubkey={new PublicKey(squadMapInfo?.version === 'v4' ? SQUADS_V4_ADDRESS : SQUADS_V3_ADDRESS)}
link
/>
</KeyValue>
<KeyValue label="Multisig Account" labelWidth={LABEL_WIDTH} row>
{squadMapInfo?.isSquad && <Address pubkey={new PublicKey(squadMapInfo.multisig)} link />}
</KeyValue>
<KeyValue label="Multisig Approval Threshold" labelWidth={LABEL_WIDTH} row>
{squadInfo?.multisig.threshold}
{' of '}
{memberCount}
</KeyValue>
{members.map((member, idx) => (
<KeyValue key={idx} label={`Multisig Member ${idx + 1}`} labelWidth={LABEL_WIDTH} row>
<Address pubkey={member} link />
</KeyValue>
))}
</SectionCard>
);
}
175 changes: 64 additions & 111 deletions app/components/account/UpgradeableLoaderAccountSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Slot } from '@components/common/Slot';
import { SolBalance } from '@components/common/SolBalance';
import { TableCardBody } from '@components/common/TableCardBody';
import { useRefreshAccount } from '@entities/account';
import { AccountDownloadDropdown } from '@features/account';
import { AccountCard } from '@features/account';
import { Account } from '@providers/accounts';
import { useCluster } from '@providers/cluster';
import { PublicKey } from '@solana/web3.js';
Expand All @@ -20,7 +20,7 @@ import {
} from '@validators/accounts/upgradeable-program';
import Link from 'next/link';
import React from 'react';
import { ExternalLink, RefreshCw } from 'react-feather';
import { RefreshCw } from 'react-feather';

import { Badge } from '@/app/components/shared/ui/badge';
import { Button } from '@/app/components/shared/ui/button';
Expand All @@ -29,6 +29,7 @@ import { ProgramSecurityTXTLabel } from '@/app/features/security-txt/ui/Security
import { useSquadsMultisigLookup } from '@/app/providers/squadsMultisig';
import { refreshAnalytics } from '@/app/shared/lib/analytics';
import { Card, CardHeader, CardTitle } from '@/app/shared/ui/Card';
import { KeyValue, LABEL_WIDTH } from '@/app/shared/ui/key-value';
import { BaseTable } from '@/app/shared/ui/Table';
import { Cluster } from '@/app/utils/cluster';
import { useClusterPath } from '@/app/utils/url';
Expand Down Expand Up @@ -84,127 +85,79 @@ export function UpgradeableProgramSection({
const label = addressLabel(account.pubkey.toBase58(), cluster);

return (
<Card ui="dashkit">
<CardHeader ui="dashkit" className="gap-2">
<CardTitle as="h3" ui="dashkit" className="flex items-center">
{programData === undefined && 'Closed '}Program Account
</CardTitle>
<Button
ui="dashkit"
variant="white"
size="sm"
onClick={() => {
refreshAnalytics.trackButtonClicked('program_section');
refresh(account.pubkey, 'parsed');
}}
>
<RefreshCw className="mr-1.5 align-text-top" size={13} />
Refresh
</Button>
<AccountDownloadDropdown pubkey={account.pubkey} space={account.space} />
</CardHeader>

<TableCardBody>
<BaseTable.Row>
<BaseTable.Cell>Address</BaseTable.Cell>
<BaseTable.Cell className="text-right">
<Address pubkey={account.pubkey} alignRight raw />
</BaseTable.Cell>
</BaseTable.Row>
{label && (
<BaseTable.Row>
<BaseTable.Cell>Address Label</BaseTable.Cell>
<BaseTable.Cell className="text-right">{label}</BaseTable.Cell>
</BaseTable.Row>
)}
<BaseTable.Row>
<BaseTable.Cell>Balance (SOL)</BaseTable.Cell>
<BaseTable.Cell className="text-right uppercase">
<SolBalance lamports={account.lamports} />
</BaseTable.Cell>
</BaseTable.Row>
<BaseTable.Row>
<BaseTable.Cell>Executable</BaseTable.Cell>
<BaseTable.Cell className="text-right">{programData !== undefined ? 'Yes' : 'No'}</BaseTable.Cell>
</BaseTable.Row>
<BaseTable.Row>
<BaseTable.Cell>Executable Data{programData === undefined && ' (Closed)'}</BaseTable.Cell>
<BaseTable.Cell className="text-right">
<Address pubkey={programAccount.programData} alignRight link />
</BaseTable.Cell>
</BaseTable.Row>
{programData !== undefined && (
<>
<BaseTable.Row>
<BaseTable.Cell>Upgradeable</BaseTable.Cell>
<BaseTable.Cell className="text-right">
{programData.authority !== null ? 'Yes' : 'No'}
</BaseTable.Cell>
</BaseTable.Row>
<BaseTable.Row>
<BaseTable.Cell>
<VerifiedLabel />
</BaseTable.Cell>
<BaseTable.Cell className="text-right">
<VerifiedProgramBadge programData={programData} pubkey={account.pubkey} />
</BaseTable.Cell>
</BaseTable.Row>
<BaseTable.Row>
<BaseTable.Cell>
<ProgramSecurityTXTLabel programPubkey={account.pubkey} />
</BaseTable.Cell>
<BaseTable.Cell className="text-right">
<ProgramSecurityTXTBadge programPubkey={account.pubkey} />
</BaseTable.Cell>
</BaseTable.Row>
<BaseTable.Row>
<BaseTable.Cell>Last Deployed Slot</BaseTable.Cell>
<BaseTable.Cell className="text-right">
<Slot slot={programData.slot} link />
</BaseTable.Cell>
</BaseTable.Row>
{programData.authority !== null && (
<>
<BaseTable.Row>
<BaseTable.Cell>Upgrade Authority</BaseTable.Cell>
<BaseTable.Cell className="text-right">
{cluster == Cluster.MainnetBeta && squadMapInfo?.isSquad ? (
<MultisigBadge pubkey={account.pubkey} />
) : null}
<Address pubkey={programData.authority} alignRight link />
</BaseTable.Cell>
</BaseTable.Row>
</>
)}
</>
)}
</TableCardBody>
</Card>
<AccountCard
title={`${programData === undefined ? 'Closed ' : ''}Program Account`}
account={account}
headerOutside
refresh={() => refresh(account.pubkey, 'parsed')}
analyticsSection="program_section"
>
<KeyValue label="Address" labelWidth={LABEL_WIDTH} row>
<Address pubkey={account.pubkey} raw />
</KeyValue>
{label && (
<KeyValue label="Address Label" labelWidth={LABEL_WIDTH} row>
{label}
</KeyValue>
)}
<KeyValue label="Balance (SOL)" labelWidth={LABEL_WIDTH} row>
<SolBalance lamports={account.lamports} />
</KeyValue>
<KeyValue label="Executable" labelWidth={LABEL_WIDTH} row>
{programData !== undefined ? 'Yes' : 'No'}
</KeyValue>
<KeyValue
label={`Executable Data${programData === undefined ? ' (Closed)' : ''}`}
labelWidth={LABEL_WIDTH}
row
>
<Address pubkey={programAccount.programData} link />
</KeyValue>
{programData !== undefined && (
<>
<KeyValue label="Upgradeable" labelWidth={LABEL_WIDTH} row>
{programData.authority !== null ? 'Yes' : 'No'}
</KeyValue>
<KeyValue label={<VerifiedLabel />} labelWidth={LABEL_WIDTH} row>
<VerifiedProgramBadge programData={programData} pubkey={account.pubkey} />
</KeyValue>
<KeyValue label={<ProgramSecurityTXTLabel />} labelWidth={LABEL_WIDTH} row>
<ProgramSecurityTXTBadge programPubkey={account.pubkey} />
</KeyValue>
<KeyValue label="Last Deployed Slot" labelWidth={LABEL_WIDTH} row>
<Slot slot={programData.slot} link />
</KeyValue>
{programData.authority !== null && (
<KeyValue label="Upgrade Authority" labelWidth={LABEL_WIDTH} row>
<div className="flex min-w-0 items-center gap-2">
<span className="min-w-0">
<Address pubkey={programData.authority} link />
</span>
{cluster == Cluster.MainnetBeta && squadMapInfo?.isSquad && (
<MultisigBadge pubkey={account.pubkey} />
)}
</div>
</KeyValue>
)}
</>
)}
</AccountCard>
);
}

function MultisigBadge({ pubkey }: { pubkey: PublicKey }) {
const programMultisigTabPath = useClusterPath({ pathname: `/address/${pubkey.toBase58()}/program-multisig` });
return (
<CardTitle as="h3" ui="dashkit">
<Badge ui="dashkit" variant="success" asChild>
<Link href={programMultisigTabPath}>Program Multisig</Link>
</Badge>
</CardTitle>
<Badge ui="tw" tone="soft" variant="success" className="shrink-0" asChild>
<Link href={programMultisigTabPath}>Program Multisig</Link>
</Badge>
);
}

function VerifiedLabel() {
return (
<InfoTooltip text="Verified builds allow users to ensure that the hash of the on-chain program matches the hash of the program of the given codebase (registry hosted by osec.io).">
<Link
rel="noopener noreferrer"
target="_blank"
href="https://github.com/Ellipsis-Labs/solana-verifiable-build"
>
<span className="text-dk-white">Verified Build</span>
<ExternalLink className="ml-1.5 align-text-top" size={13} />
</Link>
Verified Build
</InfoTooltip>
);
}
Expand Down
Loading
Loading