diff --git a/app/address/[address]/layout.tsx b/app/address/[address]/layout.tsx
index 0a8f2930..16a91894 100644
--- a/app/address/[address]/layout.tsx
+++ b/app/address/[address]/layout.tsx
@@ -630,7 +630,7 @@ function getAnchorTabs(pubkey: PublicKey, account: Account) {
tabComponents.push({
component: (
>}>
-
+
),
tab: anchorProgramTab,
@@ -653,13 +653,13 @@ function getAnchorTabs(pubkey: PublicKey, account: Account) {
return tabComponents;
}
-function AnchorProgramLink({ tab, address, pubkey }: { tab: Tab; address: string; pubkey: PublicKey }) {
+function AnchorProgramIdlLink({ tab, address, pubkey }: { tab: Tab; address: string; pubkey: PublicKey }) {
const { url } = useCluster();
- const anchorProgram = useAnchorProgram(pubkey.toString(), url);
+ const { idl } = useAnchorProgram(pubkey.toString(), url);
const anchorProgramPath = useClusterPath({ pathname: `/address/${address}/${tab.path}` });
const selectedLayoutSegment = useSelectedLayoutSegment();
const isActive = selectedLayoutSegment === tab.path;
- if (!anchorProgram) {
+ if (!idl) {
return null;
}
@@ -674,7 +674,7 @@ function AnchorProgramLink({ tab, address, pubkey }: { tab: Tab; address: string
function AccountDataLink({ address, tab, programId }: { address: string; tab: Tab; programId: PublicKey }) {
const { url } = useCluster();
- const accountAnchorProgram = useAnchorProgram(programId.toString(), url);
+ const { program: accountAnchorProgram } = useAnchorProgram(programId.toString(), url);
const accountDataPath = useClusterPath({ pathname: `/address/${address}/${tab.path}` });
const selectedLayoutSegment = useSelectedLayoutSegment();
const isActive = selectedLayoutSegment === tab.path;
diff --git a/app/components/account/AnchorAccountCard.tsx b/app/components/account/AnchorAccountCard.tsx
index 2970e448..6eac8345 100644
--- a/app/components/account/AnchorAccountCard.tsx
+++ b/app/components/account/AnchorAccountCard.tsx
@@ -10,7 +10,7 @@ import React, { useMemo } from 'react';
export function AnchorAccountCard({ account }: { account: Account }) {
const { lamports } = account;
const { url } = useCluster();
- const anchorProgram = useAnchorProgram(account.owner.toString(), url);
+ const { program: anchorProgram } = useAnchorProgram(account.owner.toString(), url);
const rawData = account.data.raw;
const programName = getAnchorProgramName(anchorProgram) || 'Unknown Program';
diff --git a/app/components/account/AnchorProgramCard.tsx b/app/components/account/AnchorProgramCard.tsx
index 20eedefd..d8bdd24e 100644
--- a/app/components/account/AnchorProgramCard.tsx
+++ b/app/components/account/AnchorProgramCard.tsx
@@ -6,9 +6,9 @@ import ReactJson from 'react-json-view';
export function AnchorProgramCard({ programId }: { programId: string }) {
const { url } = useCluster();
- const program = useAnchorProgram(programId, url);
+ const { idl } = useAnchorProgram(programId, url);
- if (!program) {
+ if (!idl) {
return null;
}
@@ -24,7 +24,7 @@ export function AnchorProgramCard({ programId }: { programId: string }) {
-
+
>
diff --git a/app/components/transaction/InstructionsSection.tsx b/app/components/transaction/InstructionsSection.tsx
index 680f69c0..88488c6d 100644
--- a/app/components/transaction/InstructionsSection.tsx
+++ b/app/components/transaction/InstructionsSection.tsx
@@ -162,7 +162,7 @@ function InstructionCard({
url: string;
}) {
const key = `${index}-${childIndex}`;
- const anchorProgram = useAnchorProgram(ix.programId.toString(), url);
+ const { program: anchorProgram } = useAnchorProgram(ix.programId.toString(), url);
if ('parsed' in ix) {
const props = {
diff --git a/app/providers/anchor.tsx b/app/providers/anchor.tsx
index c8711e05..f74735a7 100644
--- a/app/providers/anchor.tsx
+++ b/app/providers/anchor.tsx
@@ -6,15 +6,13 @@ import pako from 'pako';
import { useEffect, useMemo } from 'react';
import { useAccountInfo, useFetchAccountInfo } from './accounts';
-import { useCluster } from './cluster';
const cachedAnchorProgramPromises: Record<
string,
- void | { __type: 'promise'; promise: Promise } | { __type: 'result'; result: Program | null }
+ void | { __type: 'promise'; promise: Promise } | { __type: 'result'; result: Idl | null }
> = {};
-function useProgramElf(programAddress: string) {
- const { url } = useCluster();
+function useIdlFromSolanaProgramBinary(programAddress: string): Idl | null {
const fetchAccountInfo = useFetchAccountInfo();
const programInfo = useAccountInfo(programAddress);
const programDataAddress: string | undefined = programInfo?.data?.data.parsed?.parsed.info['programData'];
@@ -39,14 +37,13 @@ function useProgramElf(programAddress: string) {
const raw = Buffer.from(programDataInfo.data.data.raw.slice(offset));
try {
- const idl = parseIdlFromElf(raw);
- return new Program(idl, programAddress, getProvider(url));
- } catch (_e) {
+ return parseIdlFromElf(raw);
+ } catch (e) {
return null;
}
}
return null;
- }, [programDataInfo, programInfo, programAddress, url]);
+ }, [programDataInfo, programInfo]);
return param;
}
@@ -82,16 +79,21 @@ function getProvider(url: string) {
return new Provider(new Connection(url), new NodeWallet(Keypair.generate()), {});
}
-function useAnchorIdlAccount(programAddress: string, url: string): Program | null {
+function useIdlFromAnchorProgramSeed(programAddress: string, url: string): Idl | null {
const key = `${programAddress}-${url}`;
const cacheEntry = cachedAnchorProgramPromises[key];
if (cacheEntry === undefined) {
- const promise = Program.at(programAddress, getProvider(url))
- .then(program => {
+ const programId = new PublicKey(programAddress);
+ const promise = Program.fetchIdl(programId, getProvider(url))
+ .then(idl => {
+ if (!idl) {
+ throw new Error(`IDL not found for program: ${programAddress.toString()}`);
+ }
+
cachedAnchorProgramPromises[key] = {
__type: 'result',
- result: program,
+ result: idl,
};
})
.catch(_ => {
@@ -108,10 +110,19 @@ function useAnchorIdlAccount(programAddress: string, url: string): Program | nul
return cacheEntry.result;
}
-export function useAnchorProgram(programAddress: string, url: string): Program | null {
- const idlFromBinary = useProgramElf(programAddress);
- const idlFromAccount = useAnchorIdlAccount(programAddress, url);
- return idlFromBinary ?? idlFromAccount;
+export function useAnchorProgram(programAddress: string, url: string): { program: Program | null; idl: Idl | null } {
+ const idlFromBinary = useIdlFromSolanaProgramBinary(programAddress);
+ const idlFromAnchorProgram = useIdlFromAnchorProgramSeed(programAddress, url);
+ const idl = idlFromBinary ?? idlFromAnchorProgram;
+ const program: Program | null = useMemo(() => {
+ if (!idl) return null;
+ try {
+ return new Program(idl, new PublicKey(programAddress), getProvider(url));
+ } catch (e) {
+ return null;
+ }
+ }, [idl, programAddress, url]);
+ return { idl, program };
}
export type AnchorAccount = {
diff --git a/app/utils/anchor.tsx b/app/utils/anchor.tsx
index ecb692fb..5d3e54f2 100644
--- a/app/utils/anchor.tsx
+++ b/app/utils/anchor.tsx
@@ -23,7 +23,7 @@ export function AnchorProgramName({
url: string;
defaultName?: string;
}) {
- const program = useAnchorProgram(programId.toString(), url);
+ const { program } = useAnchorProgram(programId.toString(), url);
const programName = getAnchorProgramName(program) || defaultName;
return <>{programName}>;
}