feat(explorer): render program name, ix name, and account names from on chain idl for specific anchor programs (#23499)
* show titles of ix, from idl Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * remove unused Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * remaining accounts Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * fallback Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * fix from code review: remove default for the non fallback case Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * keep camelcase Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * formatting Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
78
explorer/package-lock.json
generated
78
explorer/package-lock.json
generated
@ -14,6 +14,7 @@
|
|||||||
"@cloudflare/stream-react": "^1.2.0",
|
"@cloudflare/stream-react": "^1.2.0",
|
||||||
"@metamask/jazzicon": "^2.0.0",
|
"@metamask/jazzicon": "^2.0.0",
|
||||||
"@metaplex/js": "4.12.0",
|
"@metaplex/js": "4.12.0",
|
||||||
|
"@project-serum/anchor": "^0.22.1",
|
||||||
"@project-serum/serum": "^0.13.61",
|
"@project-serum/serum": "^0.13.61",
|
||||||
"@react-hook/debounce": "^4.0.0",
|
"@react-hook/debounce": "^4.0.0",
|
||||||
"@sentry/react": "^6.16.1",
|
"@sentry/react": "^6.16.1",
|
||||||
@ -4489,17 +4490,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@project-serum/anchor": {
|
"node_modules/@project-serum/anchor": {
|
||||||
"version": "0.11.1",
|
"version": "0.22.1",
|
||||||
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.22.1.tgz",
|
||||||
"integrity": "sha512-oIdm4vTJkUy6GmE6JgqDAuQPKI7XM4TPJkjtoIzp69RZe0iAD9JP2XHx7lV1jLdYXeYHqDXfBt3zcq7W91K6PA==",
|
"integrity": "sha512-5pHeyvQhzLahIQ8aZymmDMZJAJFklN0joZdI+YIqFkK2uU/mlKr6rBLQjxysf/j1mLLiNG00tdyLfUtTAdQz7w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@project-serum/borsh": "^0.2.2",
|
"@project-serum/borsh": "^0.2.5",
|
||||||
"@solana/web3.js": "^1.17.0",
|
"@solana/web3.js": "^1.17.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"bn.js": "^5.1.2",
|
"bn.js": "^5.1.2",
|
||||||
"bs58": "^4.0.1",
|
"bs58": "^4.0.1",
|
||||||
"buffer-layout": "^1.2.0",
|
"buffer-layout": "^1.2.2",
|
||||||
"camelcase": "^5.3.1",
|
"camelcase": "^5.3.1",
|
||||||
|
"cross-fetch": "^3.1.5",
|
||||||
"crypto-hash": "^1.3.0",
|
"crypto-hash": "^1.3.0",
|
||||||
"eventemitter3": "^4.0.7",
|
"eventemitter3": "^4.0.7",
|
||||||
"find": "^0.3.0",
|
"find": "^0.3.0",
|
||||||
@ -4547,6 +4549,30 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@project-serum/serum/node_modules/@project-serum/anchor": {
|
||||||
|
"version": "0.11.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.11.1.tgz",
|
||||||
|
"integrity": "sha512-oIdm4vTJkUy6GmE6JgqDAuQPKI7XM4TPJkjtoIzp69RZe0iAD9JP2XHx7lV1jLdYXeYHqDXfBt3zcq7W91K6PA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@project-serum/borsh": "^0.2.2",
|
||||||
|
"@solana/web3.js": "^1.17.0",
|
||||||
|
"base64-js": "^1.5.1",
|
||||||
|
"bn.js": "^5.1.2",
|
||||||
|
"bs58": "^4.0.1",
|
||||||
|
"buffer-layout": "^1.2.0",
|
||||||
|
"camelcase": "^5.3.1",
|
||||||
|
"crypto-hash": "^1.3.0",
|
||||||
|
"eventemitter3": "^4.0.7",
|
||||||
|
"find": "^0.3.0",
|
||||||
|
"js-sha256": "^0.9.0",
|
||||||
|
"pako": "^2.0.3",
|
||||||
|
"snake-case": "^3.0.4",
|
||||||
|
"toml": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=11"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@project-serum/serum/node_modules/@solana/spl-token": {
|
"node_modules/@project-serum/serum/node_modules/@solana/spl-token": {
|
||||||
"version": "0.1.6",
|
"version": "0.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.6.tgz",
|
||||||
@ -4594,6 +4620,11 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@project-serum/serum/node_modules/pako": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg=="
|
||||||
|
},
|
||||||
"node_modules/@project-serum/sol-wallet-adapter": {
|
"node_modules/@project-serum/sol-wallet-adapter": {
|
||||||
"version": "0.1.8",
|
"version": "0.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/@project-serum/sol-wallet-adapter/-/sol-wallet-adapter-0.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/@project-serum/sol-wallet-adapter/-/sol-wallet-adapter-0.1.8.tgz",
|
||||||
@ -30606,17 +30637,18 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"@project-serum/anchor": {
|
"@project-serum/anchor": {
|
||||||
"version": "0.11.1",
|
"version": "0.22.1",
|
||||||
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.22.1.tgz",
|
||||||
"integrity": "sha512-oIdm4vTJkUy6GmE6JgqDAuQPKI7XM4TPJkjtoIzp69RZe0iAD9JP2XHx7lV1jLdYXeYHqDXfBt3zcq7W91K6PA==",
|
"integrity": "sha512-5pHeyvQhzLahIQ8aZymmDMZJAJFklN0joZdI+YIqFkK2uU/mlKr6rBLQjxysf/j1mLLiNG00tdyLfUtTAdQz7w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@project-serum/borsh": "^0.2.2",
|
"@project-serum/borsh": "^0.2.5",
|
||||||
"@solana/web3.js": "^1.17.0",
|
"@solana/web3.js": "^1.17.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"bn.js": "^5.1.2",
|
"bn.js": "^5.1.2",
|
||||||
"bs58": "^4.0.1",
|
"bs58": "^4.0.1",
|
||||||
"buffer-layout": "^1.2.0",
|
"buffer-layout": "^1.2.2",
|
||||||
"camelcase": "^5.3.1",
|
"camelcase": "^5.3.1",
|
||||||
|
"cross-fetch": "^3.1.5",
|
||||||
"crypto-hash": "^1.3.0",
|
"crypto-hash": "^1.3.0",
|
||||||
"eventemitter3": "^4.0.7",
|
"eventemitter3": "^4.0.7",
|
||||||
"find": "^0.3.0",
|
"find": "^0.3.0",
|
||||||
@ -30654,6 +30686,27 @@
|
|||||||
"buffer-layout": "^1.2.0"
|
"buffer-layout": "^1.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@project-serum/anchor": {
|
||||||
|
"version": "0.11.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.11.1.tgz",
|
||||||
|
"integrity": "sha512-oIdm4vTJkUy6GmE6JgqDAuQPKI7XM4TPJkjtoIzp69RZe0iAD9JP2XHx7lV1jLdYXeYHqDXfBt3zcq7W91K6PA==",
|
||||||
|
"requires": {
|
||||||
|
"@project-serum/borsh": "^0.2.2",
|
||||||
|
"@solana/web3.js": "^1.17.0",
|
||||||
|
"base64-js": "^1.5.1",
|
||||||
|
"bn.js": "^5.1.2",
|
||||||
|
"bs58": "^4.0.1",
|
||||||
|
"buffer-layout": "^1.2.0",
|
||||||
|
"camelcase": "^5.3.1",
|
||||||
|
"crypto-hash": "^1.3.0",
|
||||||
|
"eventemitter3": "^4.0.7",
|
||||||
|
"find": "^0.3.0",
|
||||||
|
"js-sha256": "^0.9.0",
|
||||||
|
"pako": "^2.0.3",
|
||||||
|
"snake-case": "^3.0.4",
|
||||||
|
"toml": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@solana/spl-token": {
|
"@solana/spl-token": {
|
||||||
"version": "0.1.6",
|
"version": "0.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.6.tgz",
|
||||||
@ -30680,6 +30733,11 @@
|
|||||||
"version": "10.0.0",
|
"version": "10.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
||||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
||||||
|
},
|
||||||
|
"pako": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"@cloudflare/stream-react": "^1.2.0",
|
"@cloudflare/stream-react": "^1.2.0",
|
||||||
"@metamask/jazzicon": "^2.0.0",
|
"@metamask/jazzicon": "^2.0.0",
|
||||||
"@metaplex/js": "4.12.0",
|
"@metaplex/js": "4.12.0",
|
||||||
|
"@project-serum/anchor": "^0.22.1",
|
||||||
"@project-serum/serum": "^0.13.61",
|
"@project-serum/serum": "^0.13.61",
|
||||||
"@react-hook/debounce": "^4.0.0",
|
"@react-hook/debounce": "^4.0.0",
|
||||||
"@sentry/react": "^6.16.1",
|
"@sentry/react": "^6.16.1",
|
||||||
|
167
explorer/src/components/instruction/GenericAnchorDetails.tsx
Normal file
167
explorer/src/components/instruction/GenericAnchorDetails.tsx
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
import {
|
||||||
|
Connection,
|
||||||
|
SignatureResult,
|
||||||
|
TransactionInstruction,
|
||||||
|
} from "@solana/web3.js";
|
||||||
|
import { InstructionCard } from "./InstructionCard";
|
||||||
|
import {
|
||||||
|
BorshInstructionCoder,
|
||||||
|
Idl,
|
||||||
|
Program,
|
||||||
|
Provider,
|
||||||
|
} from "@project-serum/anchor";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { useCluster } from "../../providers/cluster";
|
||||||
|
import { Address } from "../common/Address";
|
||||||
|
import { snakeCase } from "snake-case";
|
||||||
|
|
||||||
|
export function GenericAnchorDetailsCard(props: {
|
||||||
|
ix: TransactionInstruction;
|
||||||
|
index: number;
|
||||||
|
result: SignatureResult;
|
||||||
|
signature: string;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
|
}) {
|
||||||
|
const { ix, index, result, innerCards, childIndex } = props;
|
||||||
|
|
||||||
|
const cluster = useCluster();
|
||||||
|
|
||||||
|
const [idl, setIdl] = useState<Idl | null>();
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchIdl() {
|
||||||
|
if (idl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch on chain idl
|
||||||
|
const idl_: Idl | null = await Program.fetchIdl(ix.programId, {
|
||||||
|
connection: new Connection(cluster.url),
|
||||||
|
} as Provider);
|
||||||
|
setIdl(idl_);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchIdl();
|
||||||
|
}, [ix.programId, cluster.url, idl]);
|
||||||
|
|
||||||
|
const [programName, setProgramName] = useState<string | null>(null);
|
||||||
|
const [ixTitle, setIxTitle] = useState<string | null>(null);
|
||||||
|
const [ixAccounts, setIxAccounts] = useState<
|
||||||
|
{ name: string; isMut: boolean; isSigner: boolean; pda?: Object }[] | null
|
||||||
|
>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function parseIxDetailsUsingCoder() {
|
||||||
|
if (!idl || (programName && ixTitle && ixAccounts)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. voter_stake_registry -> voter stake registry
|
||||||
|
var _programName = idl.name.replaceAll("_", " ").trim();
|
||||||
|
// e.g. voter stake registry -> Voter Stake Registry
|
||||||
|
_programName = _programName
|
||||||
|
.toLowerCase()
|
||||||
|
.split(" ")
|
||||||
|
.map((word) => word.charAt(0).toUpperCase() + word.substring(1))
|
||||||
|
.join(" ");
|
||||||
|
setProgramName(_programName);
|
||||||
|
|
||||||
|
const coder = new BorshInstructionCoder(idl);
|
||||||
|
const decodedIx = coder.decode(ix.data);
|
||||||
|
if (!decodedIx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get ix title, pascal case it
|
||||||
|
var _ixTitle = decodedIx.name;
|
||||||
|
_ixTitle = _ixTitle.charAt(0).toUpperCase() + _ixTitle.slice(1);
|
||||||
|
setIxTitle(_ixTitle);
|
||||||
|
|
||||||
|
// get ix accounts
|
||||||
|
const idlInstructions = idl.instructions.filter(
|
||||||
|
(ix) => ix.name === decodedIx.name
|
||||||
|
);
|
||||||
|
if (idlInstructions.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIxAccounts(
|
||||||
|
idlInstructions[0].accounts as {
|
||||||
|
// type coercing since anchor doesn't export the underlying type
|
||||||
|
name: string;
|
||||||
|
isMut: boolean;
|
||||||
|
isSigner: boolean;
|
||||||
|
pda?: Object;
|
||||||
|
}[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseIxDetailsUsingCoder();
|
||||||
|
}, [
|
||||||
|
ix.programId,
|
||||||
|
ix.keys,
|
||||||
|
ix.data,
|
||||||
|
idl,
|
||||||
|
cluster,
|
||||||
|
programName,
|
||||||
|
ixTitle,
|
||||||
|
ixAccounts,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{idl && (
|
||||||
|
<InstructionCard
|
||||||
|
ix={ix}
|
||||||
|
index={index}
|
||||||
|
result={result}
|
||||||
|
title={`${programName || "Unknown"}: ${ixTitle || "Unknown"}`}
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
|
>
|
||||||
|
<tr key={ix.programId.toBase58()}>
|
||||||
|
<td>Program</td>
|
||||||
|
<td className="text-lg-end">
|
||||||
|
<Address pubkey={ix.programId} alignRight link />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{ixAccounts != null &&
|
||||||
|
ix.keys.map((am, keyIndex) => (
|
||||||
|
<tr key={keyIndex}>
|
||||||
|
<td>
|
||||||
|
<div className="me-2 d-md-inline">
|
||||||
|
{/* remaining accounts would not have a name */}
|
||||||
|
{ixAccounts[keyIndex] &&
|
||||||
|
snakeCase(ixAccounts[keyIndex].name)}
|
||||||
|
{!ixAccounts[keyIndex] &&
|
||||||
|
"remaining account #" +
|
||||||
|
(keyIndex - ixAccounts.length + 1)}
|
||||||
|
</div>
|
||||||
|
{am.isWritable && (
|
||||||
|
<span className="badge bg-info-soft me-1">Writable</span>
|
||||||
|
)}
|
||||||
|
{am.isSigner && (
|
||||||
|
<span className="badge bg-info-soft me-1">Signer</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<Address pubkey={am.pubkey} alignRight link />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</InstructionCard>
|
||||||
|
)}
|
||||||
|
{!idl && (
|
||||||
|
<InstructionCard
|
||||||
|
ix={ix}
|
||||||
|
index={index}
|
||||||
|
result={result}
|
||||||
|
title={`Unknown Program: Unknown Instruction`}
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
|
defaultRaw
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
16
explorer/src/components/instruction/anchor/types.ts
Normal file
16
explorer/src/components/instruction/anchor/types.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TransactionInstruction } from "@solana/web3.js";
|
||||||
|
|
||||||
|
// list of programs written in anchor
|
||||||
|
// - should have idl on-chain for GenericAnchorDetailsCard to work out of the box
|
||||||
|
// - before adding another program to this list, please make sure that the ix
|
||||||
|
// are decoding without any errors
|
||||||
|
const knownAnchorPrograms = [
|
||||||
|
// https://github.com/blockworks-foundation/voter-stake-registry
|
||||||
|
"4Q6WW2ouZ6V3iaNm56MTd5n2tnTm4C5fiH8miFHnAFHo",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const isInstructionFromAnAnchorProgram = (
|
||||||
|
instruction: TransactionInstruction
|
||||||
|
) => {
|
||||||
|
return knownAnchorPrograms.includes(instruction.programId.toBase58());
|
||||||
|
};
|
@ -21,8 +21,8 @@ import { WormholeDetailsCard } from "components/instruction/WormholeDetailsCard"
|
|||||||
import { UnknownDetailsCard } from "components/instruction/UnknownDetailsCard";
|
import { UnknownDetailsCard } from "components/instruction/UnknownDetailsCard";
|
||||||
import { BonfidaBotDetailsCard } from "components/instruction/BonfidaBotDetails";
|
import { BonfidaBotDetailsCard } from "components/instruction/BonfidaBotDetails";
|
||||||
import {
|
import {
|
||||||
SignatureProps,
|
|
||||||
INNER_INSTRUCTIONS_START_SLOT,
|
INNER_INSTRUCTIONS_START_SLOT,
|
||||||
|
SignatureProps,
|
||||||
} from "pages/TransactionDetailsPage";
|
} from "pages/TransactionDetailsPage";
|
||||||
import { intoTransactionInstruction } from "utils/tx";
|
import { intoTransactionInstruction } from "utils/tx";
|
||||||
import { isSerumInstruction } from "components/instruction/serum/types";
|
import { isSerumInstruction } from "components/instruction/serum/types";
|
||||||
@ -39,10 +39,12 @@ import { BpfUpgradeableLoaderDetailsCard } from "components/instruction/bpf-upgr
|
|||||||
import { VoteDetailsCard } from "components/instruction/vote/VoteDetailsCard";
|
import { VoteDetailsCard } from "components/instruction/vote/VoteDetailsCard";
|
||||||
import { isWormholeInstruction } from "components/instruction/wormhole/types";
|
import { isWormholeInstruction } from "components/instruction/wormhole/types";
|
||||||
import { AssociatedTokenDetailsCard } from "components/instruction/AssociatedTokenDetailsCard";
|
import { AssociatedTokenDetailsCard } from "components/instruction/AssociatedTokenDetailsCard";
|
||||||
import { isMangoInstruction } from "components/instruction/mango/types";
|
|
||||||
import { MangoDetailsCard } from "components/instruction/MangoDetails";
|
import { MangoDetailsCard } from "components/instruction/MangoDetails";
|
||||||
import { isPythInstruction } from "components/instruction/pyth/types";
|
import { isPythInstruction } from "components/instruction/pyth/types";
|
||||||
import { PythDetailsCard } from "components/instruction/pyth/PythDetailsCard";
|
import { PythDetailsCard } from "components/instruction/pyth/PythDetailsCard";
|
||||||
|
import { isInstructionFromAnAnchorProgram } from "../instruction/anchor/types";
|
||||||
|
import { GenericAnchorDetailsCard } from "../instruction/GenericAnchorDetails";
|
||||||
|
import { isMangoInstruction } from "../instruction/mango/types";
|
||||||
|
|
||||||
export type InstructionDetailsProps = {
|
export type InstructionDetailsProps = {
|
||||||
tx: ParsedTransaction;
|
tx: ParsedTransaction;
|
||||||
@ -214,6 +216,8 @@ function renderInstructionCard({
|
|||||||
|
|
||||||
if (isBonfidaBotInstruction(transactionIx)) {
|
if (isBonfidaBotInstruction(transactionIx)) {
|
||||||
return <BonfidaBotDetailsCard key={key} {...props} />;
|
return <BonfidaBotDetailsCard key={key} {...props} />;
|
||||||
|
} else if (isInstructionFromAnAnchorProgram(transactionIx)) {
|
||||||
|
return <GenericAnchorDetailsCard key={key} {...props} />;
|
||||||
} else if (isMangoInstruction(transactionIx)) {
|
} else if (isMangoInstruction(transactionIx)) {
|
||||||
return <MangoDetailsCard key={key} {...props} />;
|
return <MangoDetailsCard key={key} {...props} />;
|
||||||
} else if (isSerumInstruction(transactionIx)) {
|
} else if (isSerumInstruction(transactionIx)) {
|
||||||
|
Reference in New Issue
Block a user