Skip to content

Commit

Permalink
Add titles for token lending instructions (#15217)
Browse files Browse the repository at this point in the history
* feat: add lending instruction names

* chore: capitalize words
  • Loading branch information
bartosz-lipinski authored Feb 10, 2021
1 parent 9af912a commit 3adc87e
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 30 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

# production
/build
/wasm/target

# misc
.DS_Store
Expand Down
16 changes: 3 additions & 13 deletions src/components/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import Select, { InputActionMeta, ActionMeta, ValueType } from "react-select";
import StateManager from "react-select";
import {
LOADER_IDS,
PROGRAM_IDS,
PROGRAM_NAME_BY_ID,
SYSVAR_IDS,
ProgramName,
LoaderName,
SEARCHABLE_PROGRAMS,
} from "utils/tx";
import { TokenRegistry } from "tokenRegistry";
import { Cluster, useCluster } from "providers/cluster";
Expand Down Expand Up @@ -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) {
const matchedPrograms = Object.entries(PROGRAM_IDS).filter(
const matchedPrograms = Object.entries(PROGRAM_NAME_BY_ID).filter(
([address, name]) => {
return (
SEARCHABLE_PROGRAMS.includes(name) &&
Expand Down
14 changes: 14 additions & 0 deletions src/components/account/TokenHistoryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ import {
isTokenSwapInstruction,
parseTokenSwapInstructionTitle,
} from "components/instruction/token-swap/types";
import {
isTokenLendingInstruction,
parseTokenLendingInstructionTitle,
} from "components/instruction/token-lending/types";
import {
isSerumInstruction,
parseSerumInstructionTitle,
Expand Down Expand Up @@ -489,6 +493,16 @@ const TokenTransactionRow = React.memo(
reportError(error, { signature: tx.signature });
return undefined;
}
} else if (
transactionInstruction &&
isTokenLendingInstruction(transactionInstruction)
) {
try {
name = parseTokenLendingInstructionTitle(transactionInstruction);
} catch (error) {
reportError(error, { signature: tx.signature });
return undefined;
}
} else {
if (
ix.accounts.findIndex((account) =>
Expand Down
46 changes: 46 additions & 0 deletions src/components/instruction/TokenLendingDetailsCard.tsx
Original file line number Diff line number Diff line change
@@ -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
/>
);
}
35 changes: 35 additions & 0 deletions src/components/instruction/token-lending/types.ts
Original file line number Diff line number Diff line change
@@ -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];
}
4 changes: 4 additions & 0 deletions src/pages/TransactionDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ import { FetchStatus } from "providers/cache";
import { SerumDetailsCard } from "components/instruction/SerumDetailsCard";
import { Slot } from "components/common/Slot";
import { isTokenSwapInstruction } from "components/instruction/token-swap/types";
import { isTokenLendingInstruction } from "components/instruction/token-lending/types";
import { TokenSwapDetailsCard } from "components/instruction/TokenSwapDetailsCard";
import { TokenLendingDetailsCard } from "components/instruction/TokenLendingDetailsCard";
import { isSerumInstruction } from "components/instruction/serum/types";
import { MemoDetailsCard } from "components/instruction/MemoDetailsCard";
import { BigNumber } from "bignumber.js";
Expand Down Expand Up @@ -613,6 +615,8 @@ function renderInstructionCard({
return <SerumDetailsCard key={key} {...props} />;
} else if (isTokenSwapInstruction(transactionIx)) {
return <TokenSwapDetailsCard key={key} {...props} />;
} else if (isTokenLendingInstruction(transactionIx)) {
return <TokenLendingDetailsCard key={key} {...props} />;
} else {
return <UnknownDetailsCard key={key} {...props} />;
}
Expand Down
68 changes: 51 additions & 17 deletions src/utils/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,57 @@ import { TokenRegistry } from "tokenRegistry";
import { Cluster } from "providers/cluster";
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 = {
BrEAK7zGZ6dM71zUDACDqJnekihmwF15noTddWTsknjC: "Break Solana Program",
Budget1111111111111111111111111111111111111: "Budget Program",
Config1111111111111111111111111111111111111: "Config Program",
Exchange11111111111111111111111111111111111: "Exchange Program",
[StakeProgram.programId.toBase58()]: "Stake Program",
Storage111111111111111111111111111111111111: "Storage Program",
[SystemProgram.programId.toBase58()]: "System Program",
Vest111111111111111111111111111111111111111: "Vest Program",
[VOTE_PROGRAM_ID.toBase58()]: "Vote Program",
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA: "SPL Token Program",
ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL:
"SPL Associated Token Account Program",
Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo: "Memo Program",
SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8: "Token Swap Program",
export enum PROGRAM_NAMES {
BREAK_SOLANA = "Break Solana Program",
BUDGET = "Budget Program",
CONFIG = "Config Program",
EXCHANGE = "Exchange Program",
STAKE = "Stake Program",
STORAGE = "Storage Program",
SYSTEM = "System Program",
VEST = "Vest Program",
VOTE = "Vote Program",
SPL_TOKEN = "SPL Token Program",
ASSOCIATED_TOKEN = "SPL Associated Token Program",
MEMO = "Memo Program",
SWAP = "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;

export type LoaderName = typeof LOADER_IDS[keyof typeof LOADER_IDS];
Expand Down Expand Up @@ -67,7 +101,7 @@ export function addressLabel(
cluster: Cluster
): string | undefined {
return (
PROGRAM_IDS[address] ||
PROGRAM_NAME_BY_ID[address] ||
LOADER_IDS[address] ||
SYSVAR_IDS[address] ||
SYSVAR_ID[address] ||
Expand Down

0 comments on commit 3adc87e

Please sign in to comment.