-
Notifications
You must be signed in to change notification settings - Fork 669
Expand file tree
/
Copy pathAnchorAccountCard.tsx
More file actions
93 lines (85 loc) · 4.18 KB
/
Copy pathAnchorAccountCard.tsx
File metadata and controls
93 lines (85 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { ErrorCard } from '@components/common/ErrorCard';
import { BorshAccountsCoder, Idl } from '@coral-xyz/anchor';
import { IdlTypeDef } from '@coral-xyz/anchor/dist/cjs/idl';
import { useAnchorProgram } from '@entities/idl';
import { useProgramMetadataIdl } from '@entities/program-metadata';
import { Account } from '@providers/accounts';
import { useCluster } from '@providers/cluster';
import { getAnchorProgramName, mapAccountToRows } from '@utils/anchor';
import React, { useMemo } from 'react';
import { equals, toBuffer } from '@/app/shared/lib/bytes';
import { Logger } from '@/app/shared/lib/logger';
import { Card, CardHeader, CardTitle } from '@/app/shared/ui/Card';
import { BaseTable } from '@/app/shared/ui/Table';
export function AnchorAccountCard({ account }: { account: Account }) {
const { lamports } = account;
const { url, cluster } = useCluster();
const { program: anchorProgram } = useAnchorProgram(account.owner.toString(), url, cluster);
const { programMetadataIdl } = useProgramMetadataIdl(account.owner.toString(), url, cluster);
const rawData = account.data.raw;
// Prefer the legacy Anchor IDL; fall back to an Anchor-format IDL published via the Program
// Metadata Program so PMP-only programs (no on-chain Anchor IDL account) decode account data too.
const idl: Idl | undefined = useMemo(() => {
if (anchorProgram?.idl) return anchorProgram.idl;
const pmp = programMetadataIdl as Idl | undefined;
return pmp && Array.isArray(pmp.accounts) ? pmp : undefined;
}, [anchorProgram, programMetadataIdl]);
const programName =
getAnchorProgramName(anchorProgram) ||
(idl?.metadata as { name?: string } | undefined)?.name ||
'Unknown Program';
const { decodedAccountData, accountDef } = useMemo(() => {
let decodedAccountData: any | null = null;
let accountDef: IdlTypeDef | undefined = undefined;
if (idl && rawData) {
try {
const coder = new BorshAccountsCoder(idl);
const account = idl.accounts?.find((accountType: any) =>
equals(rawData.slice(0, 8), coder.accountDiscriminator(accountType.name)),
);
if (account) {
accountDef = idl.types?.find((type: any) => type.name === account.name);
try {
decodedAccountData = coder.decode(account.name, toBuffer(rawData));
} catch (err) {
Logger.debug('[components:anchor-account] Failed to decode account data', { error: err });
}
}
} catch (err) {
Logger.debug('[components:anchor-account] Failed to build accounts coder', { error: err });
}
}
return {
accountDef,
decodedAccountData,
};
}, [idl, rawData]);
if (lamports === undefined) return null;
if (!idl) return <ErrorCard text="No Anchor IDL found" />;
if (!decodedAccountData || !accountDef) {
return <ErrorCard text="Failed to decode account data according to the public Anchor interface" />;
}
return (
<div>
<Card ui="dashkit">
<CardHeader ui="dashkit">
<CardTitle as="h3" ui="dashkit">
{programName}: {accountDef.name.charAt(0).toUpperCase() + accountDef.name.slice(1)}
</CardTitle>
</CardHeader>
<BaseTable ui="dashkit" variant="card" nowrap>
<BaseTable.Head>
<BaseTable.Row>
<BaseTable.HeaderCell className="w-px">Field</BaseTable.HeaderCell>
<BaseTable.HeaderCell className="w-px">Type</BaseTable.HeaderCell>
<BaseTable.HeaderCell className="w-px">Value</BaseTable.HeaderCell>
</BaseTable.Row>
</BaseTable.Head>
<BaseTable.Body>
{mapAccountToRows(decodedAccountData, accountDef as IdlTypeDef, idl)}
</BaseTable.Body>
</BaseTable>
</Card>
</div>
);
}