Add titles for token lending instructions (#15217)
* feat: add lending instruction names * chore: capitalize words
This commit is contained in:
parent
948819dfa8
commit
a0ba59a1ea
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
# production
|
# production
|
||||||
/build
|
/build
|
||||||
|
/wasm/target
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
@ -5,10 +5,10 @@ import Select, { InputActionMeta, ActionMeta, ValueType } from "react-select";
|
||||||
import StateManager from "react-select";
|
import StateManager from "react-select";
|
||||||
import {
|
import {
|
||||||
LOADER_IDS,
|
LOADER_IDS,
|
||||||
PROGRAM_IDS,
|
PROGRAM_NAME_BY_ID,
|
||||||
SYSVAR_IDS,
|
SYSVAR_IDS,
|
||||||
ProgramName,
|
|
||||||
LoaderName,
|
LoaderName,
|
||||||
|
SEARCHABLE_PROGRAMS,
|
||||||
} from "utils/tx";
|
} from "utils/tx";
|
||||||
import { TokenRegistry } from "tokenRegistry";
|
import { TokenRegistry } from "tokenRegistry";
|
||||||
import { Cluster, useCluster } from "providers/cluster";
|
import { Cluster, useCluster } from "providers/cluster";
|
||||||
|
@ -64,18 +64,8 @@ export function SearchBar() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SEARCHABLE_PROGRAMS: ProgramName[] = [
|
|
||||||
"Break Solana Program",
|
|
||||||
"Config Program",
|
|
||||||
"Stake Program",
|
|
||||||
"System Program",
|
|
||||||
"Vote Program",
|
|
||||||
"SPL Token Program",
|
|
||||||
"Memo Program",
|
|
||||||
];
|
|
||||||
|
|
||||||
function buildProgramOptions(search: string) {
|
function buildProgramOptions(search: string) {
|
||||||
const matchedPrograms = Object.entries(PROGRAM_IDS).filter(
|
const matchedPrograms = Object.entries(PROGRAM_NAME_BY_ID).filter(
|
||||||
([address, name]) => {
|
([address, name]) => {
|
||||||
return (
|
return (
|
||||||
SEARCHABLE_PROGRAMS.includes(name) &&
|
SEARCHABLE_PROGRAMS.includes(name) &&
|
||||||
|
|
|
@ -37,6 +37,10 @@ import {
|
||||||
isTokenSwapInstruction,
|
isTokenSwapInstruction,
|
||||||
parseTokenSwapInstructionTitle,
|
parseTokenSwapInstructionTitle,
|
||||||
} from "components/instruction/token-swap/types";
|
} from "components/instruction/token-swap/types";
|
||||||
|
import {
|
||||||
|
isTokenLendingInstruction,
|
||||||
|
parseTokenLendingInstructionTitle,
|
||||||
|
} from "components/instruction/token-lending/types";
|
||||||
import {
|
import {
|
||||||
isSerumInstruction,
|
isSerumInstruction,
|
||||||
parseSerumInstructionTitle,
|
parseSerumInstructionTitle,
|
||||||
|
@ -489,6 +493,16 @@ const TokenTransactionRow = React.memo(
|
||||||
reportError(error, { signature: tx.signature });
|
reportError(error, { signature: tx.signature });
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
} else if (
|
||||||
|
transactionInstruction &&
|
||||||
|
isTokenLendingInstruction(transactionInstruction)
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
name = parseTokenLendingInstructionTitle(transactionInstruction);
|
||||||
|
} catch (error) {
|
||||||
|
reportError(error, { signature: tx.signature });
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
ix.accounts.findIndex((account) =>
|
ix.accounts.findIndex((account) =>
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import React from "react";
|
||||||
|
import { TransactionInstruction, SignatureResult } from "@solana/web3.js";
|
||||||
|
import { InstructionCard } from "./InstructionCard";
|
||||||
|
import { useCluster } from "providers/cluster";
|
||||||
|
import { reportError } from "utils/sentry";
|
||||||
|
import { parseTokenLendingInstructionTitle } from "./token-lending/types";
|
||||||
|
|
||||||
|
export function TokenLendingDetailsCard({
|
||||||
|
ix,
|
||||||
|
index,
|
||||||
|
result,
|
||||||
|
signature,
|
||||||
|
innerCards,
|
||||||
|
childIndex,
|
||||||
|
}: {
|
||||||
|
ix: TransactionInstruction;
|
||||||
|
index: number;
|
||||||
|
result: SignatureResult;
|
||||||
|
signature: string;
|
||||||
|
innerCards?: JSX.Element[];
|
||||||
|
childIndex?: number;
|
||||||
|
}) {
|
||||||
|
const { url } = useCluster();
|
||||||
|
|
||||||
|
let title;
|
||||||
|
try {
|
||||||
|
title = parseTokenLendingInstructionTitle(ix);
|
||||||
|
} catch (error) {
|
||||||
|
reportError(error, {
|
||||||
|
url: url,
|
||||||
|
signature: signature,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InstructionCard
|
||||||
|
ix={ix}
|
||||||
|
index={index}
|
||||||
|
result={result}
|
||||||
|
title={`Token Lending: ${title || "Unknown"}`}
|
||||||
|
innerCards={innerCards}
|
||||||
|
childIndex={childIndex}
|
||||||
|
defaultRaw
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { TransactionInstruction } from "@solana/web3.js";
|
||||||
|
|
||||||
|
export const PROGRAM_IDS: string[] = [
|
||||||
|
"LendZqTs7gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi", // mainnet / testnet / devnet
|
||||||
|
];
|
||||||
|
|
||||||
|
const INSTRUCTION_LOOKUP: { [key: number]: string } = {
|
||||||
|
0: "Initialize Lending Market",
|
||||||
|
1: "Initialize Reserve",
|
||||||
|
2: "Initialize Obligation",
|
||||||
|
3: "Reserve Deposit",
|
||||||
|
4: "Reserve Withdraw",
|
||||||
|
5: "Borrow",
|
||||||
|
6: "Repay Loan",
|
||||||
|
7: "Liquidate Loan",
|
||||||
|
8: "Accrue Interest",
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isTokenLendingInstruction(
|
||||||
|
instruction: TransactionInstruction
|
||||||
|
): boolean {
|
||||||
|
return PROGRAM_IDS.includes(instruction.programId.toBase58());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseTokenLendingInstructionTitle(
|
||||||
|
instruction: TransactionInstruction
|
||||||
|
): string {
|
||||||
|
const code = instruction.data[0];
|
||||||
|
|
||||||
|
if (!(code in INSTRUCTION_LOOKUP)) {
|
||||||
|
throw new Error(`Unrecognized Token Swap instruction code: ${code}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return INSTRUCTION_LOOKUP[code];
|
||||||
|
}
|
|
@ -37,7 +37,9 @@ import { FetchStatus } from "providers/cache";
|
||||||
import { SerumDetailsCard } from "components/instruction/SerumDetailsCard";
|
import { SerumDetailsCard } from "components/instruction/SerumDetailsCard";
|
||||||
import { Slot } from "components/common/Slot";
|
import { Slot } from "components/common/Slot";
|
||||||
import { isTokenSwapInstruction } from "components/instruction/token-swap/types";
|
import { isTokenSwapInstruction } from "components/instruction/token-swap/types";
|
||||||
|
import { isTokenLendingInstruction } from "components/instruction/token-lending/types";
|
||||||
import { TokenSwapDetailsCard } from "components/instruction/TokenSwapDetailsCard";
|
import { TokenSwapDetailsCard } from "components/instruction/TokenSwapDetailsCard";
|
||||||
|
import { TokenLendingDetailsCard } from "components/instruction/TokenLendingDetailsCard";
|
||||||
import { isSerumInstruction } from "components/instruction/serum/types";
|
import { isSerumInstruction } from "components/instruction/serum/types";
|
||||||
import { MemoDetailsCard } from "components/instruction/MemoDetailsCard";
|
import { MemoDetailsCard } from "components/instruction/MemoDetailsCard";
|
||||||
import { BigNumber } from "bignumber.js";
|
import { BigNumber } from "bignumber.js";
|
||||||
|
@ -613,6 +615,8 @@ function renderInstructionCard({
|
||||||
return <SerumDetailsCard key={key} {...props} />;
|
return <SerumDetailsCard key={key} {...props} />;
|
||||||
} else if (isTokenSwapInstruction(transactionIx)) {
|
} else if (isTokenSwapInstruction(transactionIx)) {
|
||||||
return <TokenSwapDetailsCard key={key} {...props} />;
|
return <TokenSwapDetailsCard key={key} {...props} />;
|
||||||
|
} else if (isTokenLendingInstruction(transactionIx)) {
|
||||||
|
return <TokenLendingDetailsCard key={key} {...props} />;
|
||||||
} else {
|
} else {
|
||||||
return <UnknownDetailsCard key={key} {...props} />;
|
return <UnknownDetailsCard key={key} {...props} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,23 +19,57 @@ import { TokenRegistry } from "tokenRegistry";
|
||||||
import { Cluster } from "providers/cluster";
|
import { Cluster } from "providers/cluster";
|
||||||
import { SerumMarketRegistry } from "serumMarketRegistry";
|
import { SerumMarketRegistry } from "serumMarketRegistry";
|
||||||
|
|
||||||
export type ProgramName = typeof PROGRAM_IDS[keyof typeof PROGRAM_IDS];
|
export type ProgramName = typeof PROGRAM_NAME_BY_ID[keyof typeof PROGRAM_NAME_BY_ID];
|
||||||
|
|
||||||
export const PROGRAM_IDS = {
|
export enum PROGRAM_NAMES {
|
||||||
BrEAK7zGZ6dM71zUDACDqJnekihmwF15noTddWTsknjC: "Break Solana Program",
|
BREAK_SOLANA = "Break Solana Program",
|
||||||
Budget1111111111111111111111111111111111111: "Budget Program",
|
BUDGET = "Budget Program",
|
||||||
Config1111111111111111111111111111111111111: "Config Program",
|
CONFIG = "Config Program",
|
||||||
Exchange11111111111111111111111111111111111: "Exchange Program",
|
EXCHANGE = "Exchange Program",
|
||||||
[StakeProgram.programId.toBase58()]: "Stake Program",
|
STAKE = "Stake Program",
|
||||||
Storage111111111111111111111111111111111111: "Storage Program",
|
STORAGE = "Storage Program",
|
||||||
[SystemProgram.programId.toBase58()]: "System Program",
|
SYSTEM = "System Program",
|
||||||
Vest111111111111111111111111111111111111111: "Vest Program",
|
VEST = "Vest Program",
|
||||||
[VOTE_PROGRAM_ID.toBase58()]: "Vote Program",
|
VOTE = "Vote Program",
|
||||||
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA: "SPL Token Program",
|
SPL_TOKEN = "SPL Token Program",
|
||||||
ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL:
|
ASSOCIATED_TOKEN = "SPL Associated Token Program",
|
||||||
"SPL Associated Token Account Program",
|
MEMO = "Memo Program",
|
||||||
Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo: "Memo Program",
|
SWAP = "Swap Program",
|
||||||
SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8: "Token Swap Program",
|
LENDING = "Lending Program",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SEARCHABLE_PROGRAMS: ProgramName[] = [
|
||||||
|
PROGRAM_NAMES.BREAK_SOLANA,
|
||||||
|
PROGRAM_NAMES.BUDGET,
|
||||||
|
PROGRAM_NAMES.CONFIG,
|
||||||
|
PROGRAM_NAMES.EXCHANGE,
|
||||||
|
PROGRAM_NAMES.STAKE,
|
||||||
|
PROGRAM_NAMES.STORAGE,
|
||||||
|
PROGRAM_NAMES.SYSTEM,
|
||||||
|
PROGRAM_NAMES.VEST,
|
||||||
|
PROGRAM_NAMES.VOTE,
|
||||||
|
PROGRAM_NAMES.SPL_TOKEN,
|
||||||
|
PROGRAM_NAMES.ASSOCIATED_TOKEN,
|
||||||
|
PROGRAM_NAMES.MEMO,
|
||||||
|
PROGRAM_NAMES.SWAP,
|
||||||
|
PROGRAM_NAMES.LENDING,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const PROGRAM_NAME_BY_ID = {
|
||||||
|
BrEAK7zGZ6dM71zUDACDqJnekihmwF15noTddWTsknjC: PROGRAM_NAMES.BREAK_SOLANA,
|
||||||
|
Budget1111111111111111111111111111111111111: PROGRAM_NAMES.BUDGET,
|
||||||
|
Config1111111111111111111111111111111111111: PROGRAM_NAMES.CONFIG,
|
||||||
|
Exchange11111111111111111111111111111111111: PROGRAM_NAMES.EXCHANGE,
|
||||||
|
[StakeProgram.programId.toBase58()]: PROGRAM_NAMES.STAKE,
|
||||||
|
Storage111111111111111111111111111111111111: PROGRAM_NAMES.STORAGE,
|
||||||
|
[SystemProgram.programId.toBase58()]: PROGRAM_NAMES.SYSTEM,
|
||||||
|
Vest111111111111111111111111111111111111111: PROGRAM_NAMES.VEST,
|
||||||
|
[VOTE_PROGRAM_ID.toBase58()]: PROGRAM_NAMES.VOTE,
|
||||||
|
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA: PROGRAM_NAMES.SPL_TOKEN,
|
||||||
|
ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL: PROGRAM_NAMES.ASSOCIATED_TOKEN,
|
||||||
|
Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo: PROGRAM_NAMES.MEMO,
|
||||||
|
SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8: PROGRAM_NAMES.SWAP,
|
||||||
|
LendZqTs7gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi: PROGRAM_NAMES.LENDING,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type LoaderName = typeof LOADER_IDS[keyof typeof LOADER_IDS];
|
export type LoaderName = typeof LOADER_IDS[keyof typeof LOADER_IDS];
|
||||||
|
@ -67,7 +101,7 @@ export function addressLabel(
|
||||||
cluster: Cluster
|
cluster: Cluster
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
return (
|
return (
|
||||||
PROGRAM_IDS[address] ||
|
PROGRAM_NAME_BY_ID[address] ||
|
||||||
LOADER_IDS[address] ||
|
LOADER_IDS[address] ||
|
||||||
SYSVAR_IDS[address] ||
|
SYSVAR_IDS[address] ||
|
||||||
SYSVAR_ID[address] ||
|
SYSVAR_ID[address] ||
|
||||||
|
|
Loading…
Reference in New Issue