diff --git a/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBox.tsx b/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBox.tsx
index 15a4201ee8..baa542d32d 100644
--- a/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBox.tsx
+++ b/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBox.tsx
@@ -5,7 +5,7 @@ import { ActionType } from "@mrgnlabs/marginfi-v2-ui-state";
import { WSOL_MINT, numeralFormatter } from "@mrgnlabs/mrgn-common";
import { ChevronDownIcon } from "@radix-ui/react-icons";
import { useMrgnlendStore, useUiStore } from "~/store";
-import { MarginfiActionParams, closeBalance, executeLendingAction } from "~/utils";
+import { MarginfiActionParams, closeBalance, cn, executeLendingAction } from "~/utils";
import { LendingModes } from "~/types";
import { useWalletContext } from "~/hooks/useWalletContext";
@@ -20,15 +20,15 @@ import { IconWallet } from "~/components/ui/icons";
import { ActionBoxActions } from "./ActionBoxActions";
export const ActionBox = () => {
- const [mfiClient, nativeSolBalance, setIsRefreshingStore, fetchMrgnlendState, selectedAccount] = useMrgnlendStore(
- (state) => [
+ const [mfiClient, nativeSolBalance, setIsRefreshingStore, fetchMrgnlendState, selectedAccount, accountSummary] =
+ useMrgnlendStore((state) => [
state.marginfiClient,
state.nativeSolBalance,
state.setIsRefreshingStore,
state.fetchMrgnlendState,
state.selectedAccount,
- ]
- );
+ state.accountSummary,
+ ]);
const [lendingMode, setLendingMode, actionMode, setActionMode, selectedToken, setSelectedToken] = useUiStore(
(state) => [
state.lendingMode,
@@ -92,31 +92,84 @@ export const ActionBox = () => {
}
}, [lendingMode, selectedToken, setAmount, setActionMode]);
+ const liquidationPrice = React.useMemo(() => {
+ const isActive = selectedToken?.isActive;
+ const isLending = lendingMode === LendingModes.LEND;
+ let liquidationPrice = 0;
+
+ if (isActive) {
+ if (!amount || amount === 0 || isLending || !selectedAccount || !selectedToken) {
+ liquidationPrice = selectedToken?.position.liquidationPrice ?? 0;
+ } else {
+ const borrowed = selectedToken?.position.amount ?? 0;
+
+ liquidationPrice =
+ selectedAccount.computeLiquidationPriceForBankAmount(selectedToken?.address, isLending, amount + borrowed) ??
+ 0;
+ }
+ }
+
+ return liquidationPrice;
+ }, [selectedToken, amount, lendingMode]);
+
+ const healthColorLiquidation = React.useMemo(() => {
+ const isActive = selectedToken?.isActive;
+
+ if (isActive) {
+ const price = selectedToken.info.oraclePrice.price.toNumber();
+ const safety = liquidationPrice / price;
+ let color: string;
+ if (safety >= 0.5) {
+ color = "#75BA80"; // green color " : "#",
+ } else if (safety >= 0.25) {
+ color = "#B8B45F"; // yellow color
+ } else {
+ color = "#CF6F6F"; // red color
+ }
+
+ return color;
+ } else {
+ return "#fff";
+ }
+ }, [selectedToken, liquidationPrice]);
+
React.useEffect(() => {
- if (!selectedToken || !amount) {
+ if (!selectedToken) {
setPreview([]);
return;
}
+ const isActive = selectedToken?.isActive;
+ let supplied = 0;
+ let borrowed = 0;
+
+ if (isActive) {
+ const isLending = selectedToken?.position?.isLending;
+ if (isLending) supplied = selectedToken?.position.amount ?? 0;
+ else borrowed = selectedToken?.position.amount ?? 0;
+ }
+ const healthFactor = accountSummary.healthFactor;
+
setPreview([
{
- key: "Your deposited amount",
- value: `${amount} ${selectedToken.meta.tokenSymbol}`,
+ key: "Supplied amount",
+ value: `${numeralFormatter(supplied)}`,
},
{
- key: "Liquidation price",
- value: usdFormatter.format(amount),
+ key: "Borrowed amount",
+ value: `${numeralFormatter(borrowed)}`,
},
{
- key: "Some propertya",
- value: "--",
+ key: "Liquidation price",
+ value:
+ liquidationPrice > 0.01 ? usdFormatter.format(liquidationPrice) : `$${liquidationPrice.toExponential(2)}`,
},
{
- key: "Some propertyb",
- value: "--",
+ key: "Health factor",
+ value: `${numeralFormatter(healthFactor * 100)}%`,
},
]);
- }, [selectedToken, amount]);
+ }, [selectedToken, amount, liquidationPrice]);
React.useEffect(() => {
if (!selectedToken || !amountInputRef.current) return;
@@ -204,7 +257,7 @@ export const ActionBox = () => {
!hasLSTDialogShown.includes(selectedToken.meta.tokenSymbol as LSTDialogVariants)
) {
setHasLSTDialogShown((prev) => [...prev, selectedToken.meta.tokenSymbol as LSTDialogVariants]);
- setLSTDialogVariant(selectedToken.meta.tokenSymbol);
+ setLSTDialogVariant(selectedToken.meta.tokenSymbol as LSTDialogVariants);
setIsLSTDialogOpen(true);
setLSTDialogCallback(() => action);
@@ -219,7 +272,7 @@ export const ActionBox = () => {
!hasLSTDialogShown.includes(selectedToken.meta.tokenSymbol as LSTDialogVariants)
) {
setHasLSTDialogShown((prev) => [...prev, selectedToken.meta.tokenSymbol as LSTDialogVariants]);
- setLSTDialogVariant(selectedToken.meta.tokenSymbol);
+ setLSTDialogVariant(selectedToken.meta.tokenSymbol as LSTDialogVariants);
return;
}
}, [
@@ -321,12 +374,20 @@ export const ActionBox = () => {
handleAction={() => (showCloseBalance ? handleCloseBalance() : handleLendingAction())}
isLoading={isLoading}
/>
- {selectedToken !== null && amount !== null && preview.length > 0 && (
+ {selectedToken !== null && preview.length > 0 && (
- {preview.map((item) => (
+ {preview.map((item, idx) => (
{item.key}
- {item.value}
+
+ {item.value}
+
))}
diff --git a/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxActions.tsx b/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxActions.tsx
index e45344f546..c9e4ca97e8 100644
--- a/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxActions.tsx
+++ b/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxActions.tsx
@@ -6,6 +6,7 @@ import { useUiStore } from "~/store";
import { Button } from "~/components/ui/button";
import { IconLoader } from "~/components/ui/icons";
+import { useWalletContext } from "~/hooks/useWalletContext";
type ActionBoxActionsProps = {
amount: number;
@@ -23,13 +24,17 @@ export const ActionBoxActions = ({
handleAction,
}: ActionBoxActionsProps) => {
const [actionMode, selectedToken] = useUiStore((state) => [state.actionMode, state.selectedToken]);
+ const { connected } = useWalletContext();
const isActionDisabled = React.useMemo(() => {
const isValidInput = amount > 0;
- return ((maxAmount === 0 || !isValidInput) && !showCloseBalance) || isLoading;
+ return ((maxAmount === 0 || !isValidInput) && !showCloseBalance) || isLoading || !connected;
}, [amount, showCloseBalance, maxAmount, isLoading]);
const actionText = React.useMemo(() => {
+ if (!connected) {
+ return "Connect your wallet";
+ }
if (!selectedToken) {
return "Select token and amount";
}
@@ -37,7 +42,6 @@ export const ActionBoxActions = ({
if (showCloseBalance) {
return "Close account";
}
- console.log({ actionMode });
if (maxAmount === 0) {
switch (actionMode) {
@@ -59,7 +63,7 @@ export const ActionBoxActions = ({
}
return actionMode;
- }, [actionMode, amount, selectedToken, maxAmount, showCloseBalance]);
+ }, [actionMode, amount, selectedToken, connected, maxAmount, showCloseBalance]);
return (
diff --git a/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxDialog.tsx b/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxDialog.tsx
index 4fad8faf58..966d48fdad 100644
--- a/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxDialog.tsx
+++ b/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxDialog.tsx
@@ -14,7 +14,7 @@ export const ActionBoxDialog = ({ children }: ActionBoxDialogProps) => {
return (
setIsDialogOpen(open)}>
{children}
-
+
diff --git a/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxTokens.tsx b/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxTokens.tsx
index f1a179465c..4e7910ccd0 100644
--- a/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxTokens.tsx
+++ b/apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBoxTokens.tsx
@@ -9,6 +9,7 @@ import { useMrgnlendStore, useUiStore } from "~/store";
import { cn } from "~/utils";
+import { useWalletContext } from "~/hooks/useWalletContext";
import { Popover, PopoverContent, PopoverTrigger } from "~/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "~/components/ui/command";
import { Button } from "~/components/ui/button";
@@ -30,6 +31,7 @@ export const ActionBoxTokens = ({ currentToken, setCurrentToken }: ActionBoxToke
const [lendingMode] = useUiStore((state) => [state.lendingMode]);
const [searchQuery, setSearchQuery] = React.useState("");
const [isTokenPopoverOpen, setIsTokenPopoverOpen] = React.useState(false);
+ const { connected } = useWalletContext();
const calculateRate = React.useCallback(
(bank: ExtendedBankInfo) =>
@@ -160,7 +162,7 @@ export const ActionBoxTokens = ({ currentToken, setCurrentToken }: ActionBoxToke
No tokens found.
- {lendingMode === LendingModes.LEND && filteredBanksUserOwns.length > 0 && (
+ {lendingMode === LendingModes.LEND && connected && filteredBanksUserOwns.length > 0 && (
{filteredBanksUserOwns.slice(0, searchQuery.length === 0 ? 5 : 3).map((bank, index) => (
)}
- {(searchQuery.length > 0 || lendingMode === LendingModes.BORROW) && filteredBanks.length > 0 && (
-
- {filteredBanks.slice(0, searchQuery.length === 0 ? 5 : 3).map((bank, index) => (
- {
- setCurrentToken(
- extendedBankInfos.find(
- (bankInfo) => bankInfo.address.toString().toLowerCase() === currentValue
- ) ?? null
- );
- setIsTokenPopoverOpen(false);
- }}
- className={cn(
- "cursor-pointer font-medium flex items-center justify-between gap-2 data-[selected=true]:bg-background-gray-light data-[selected=true]:text-white",
- lendingMode === LendingModes.LEND && "py-2",
- lendingMode === LendingModes.BORROW && "h-[60px]"
- )}
- >
-
-
- ))}
-
- )}
+ {(searchQuery.length > 0 || lendingMode === LendingModes.BORROW || !connected) &&
+ filteredBanks.length > 0 && (
+
+ {filteredBanks.slice(0, searchQuery.length === 0 ? 5 : 3).map((bank, index) => (
+ {
+ setCurrentToken(
+ extendedBankInfos.find(
+ (bankInfo) => bankInfo.address.toString().toLowerCase() === currentValue
+ ) ?? null
+ );
+ setIsTokenPopoverOpen(false);
+ }}
+ className={cn(
+ "cursor-pointer font-medium flex items-center justify-between gap-2 data-[selected=true]:bg-background-gray-light data-[selected=true]:text-white",
+ lendingMode === LendingModes.LEND && "py-2",
+ lendingMode === LendingModes.BORROW && "h-[60px]"
+ )}
+ >
+
+
+ ))}
+
+ )}
diff --git a/apps/marginfi-v2-ui/src/components/common/AssetList/AssetListFilters.tsx b/apps/marginfi-v2-ui/src/components/common/AssetList/AssetListFilters.tsx
index e5ed81171e..c07686d2bd 100644
--- a/apps/marginfi-v2-ui/src/components/common/AssetList/AssetListFilters.tsx
+++ b/apps/marginfi-v2-ui/src/components/common/AssetList/AssetListFilters.tsx
@@ -9,11 +9,13 @@ import { MrgnContainedSwitch } from "~/components/common/MrgnContainedSwitch";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/components/ui/select";
import { IconFilter, IconSortAscending, IconSortDescending } from "~/components/ui/icons";
-import { LendingModes, PoolTypes, SortType, sortDirection, SortAssetOption } from "~/types";
+import { LendingModes, PoolTypes, SortType, sortDirection, SortAssetOption, UserMode } from "~/types";
export const AssetListFilters = () => {
const { connected } = useWalletContext();
const [
+ userMode,
+ setUserMode,
lendingMode,
setLendingMode,
poolFilter,
@@ -24,6 +26,8 @@ export const AssetListFilters = () => {
sortOption,
setSortOption,
] = useUiStore((state) => [
+ state.userMode,
+ state.setUserMode,
state.lendingMode,
state.setLendingMode,
state.poolFilter,
@@ -38,87 +42,108 @@ export const AssetListFilters = () => {
return (
-
-
setLendingMode(lendingMode === LendingModes.LEND ? LendingModes.BORROW : LendingModes.LEND)}
- />
+
+
+
+ setLendingMode(lendingMode === LendingModes.LEND ? LendingModes.BORROW : LendingModes.LEND)
+ }
+ />
+
+
+
+
{
+ setUserMode(userMode === UserMode.PRO ? UserMode.LITE : UserMode.PRO);
+ }}
+ inputProps={{ "aria-label": "controlled" }}
+ className={cn(`${!connected && "pointer-events-none"}`)}
+ />
+ Pro mode
+
+
- {
- e.stopPropagation();
- if (connected) return;
- setIsWalletAuthDialogOpen(true);
- }}
- >
-
{
- setIsFilteredUserPositions(!isFilteredUserPositions);
- setPoolFilter(PoolTypes.ALL);
+ {userMode === UserMode.PRO && (
+ {
+ e.stopPropagation();
+ if (connected) return;
+ setIsWalletAuthDialogOpen(true);
}}
- inputProps={{ "aria-label": "controlled" }}
- className={cn(!connected && "pointer-events-none")}
- />
-
Filter my positions
-
-
-
-
{
- setPoolFilter(value as PoolTypes);
+ >
+ {
+ setIsFilteredUserPositions(!isFilteredUserPositions);
+ setPoolFilter(PoolTypes.ALL);
}}
- >
-
-
-
-
-
-
-
- All pools
- Isolated pools
- Stablecoins
- SOL / LST
-
-
+ inputProps={{ "aria-label": "controlled" }}
+ className={cn(!connected && "pointer-events-none")}
+ />
+
Filter my positions
-
-
setSortOption(SORT_OPTIONS_MAP[value as SortType])}
- >
-
-
- {sortOption.direction === sortDirection.ASC ? (
-
- ) : (
-
- )}
-
-
-
-
- {Object.values(SORT_OPTIONS_MAP).map((option) => {
- const opt = option as SortAssetOption;
- return (
-
-
- {lendingMode === LendingModes.LEND || !opt.borrowLabel ? opt.label : opt.borrowLabel}
-
-
- );
- })}
-
-
+ )}
+ {userMode === UserMode.PRO && (
+
+
+
{
+ setPoolFilter(value as PoolTypes);
+ }}
+ >
+
+
+
+
+
+
+
+ All pools
+ Isolated pools
+ Stablecoins
+ SOL / LST
+
+
+
+
+
setSortOption(SORT_OPTIONS_MAP[value as SortType])}
+ >
+
+
+ {sortOption.direction === sortDirection.ASC ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {Object.values(SORT_OPTIONS_MAP).map((option) => {
+ const opt = option as SortAssetOption;
+ return (
+
+
+ {lendingMode === LendingModes.LEND || !opt.borrowLabel ? opt.label : opt.borrowLabel}
+
+
+ );
+ })}
+
+
+
-
+ )}
);
diff --git a/apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowAction.tsx b/apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowAction.tsx
index 7dc50d4290..b5a9becafd 100644
--- a/apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowAction.tsx
+++ b/apps/marginfi-v2-ui/src/components/common/AssetList/AssetRowAction.tsx
@@ -1,14 +1,15 @@
import { FC, ReactNode } from "react";
import { Button, ButtonProps } from "@mui/material";
+import { cn } from "~/utils";
interface AssetRowActionProps extends ButtonProps {
children?: ReactNode;
bgColor?: string;
}
-const AssetRowAction: FC = ({ children, disabled, bgColor, ...otherProps }) => (
+const AssetRowAction: FC = ({ children, disabled, bgColor, className, ...otherProps }) => (
{
interest={accountInterest}
/>
-
-
+
+
Supplied
{accountSupplied}
@@ -141,7 +141,7 @@ export const Portfolio = () => {
)}
-
+
Borrowed
{accountBorrowed}
diff --git a/apps/marginfi-v2-ui/src/components/common/Portfolio/UserStats/UserStats.tsx b/apps/marginfi-v2-ui/src/components/common/Portfolio/UserStats/UserStats.tsx
index bc16c83d1b..a94ae1c975 100644
--- a/apps/marginfi-v2-ui/src/components/common/Portfolio/UserStats/UserStats.tsx
+++ b/apps/marginfi-v2-ui/src/components/common/Portfolio/UserStats/UserStats.tsx
@@ -9,7 +9,7 @@ interface props {
export const UserStats: FC = ({ supplied, borrowed, netValue, interest }) => {
return (
-
+
@@ -19,7 +19,7 @@ export const UserStats: FC
= ({ supplied, borrowed, netValue, interest })
};
const Stat = ({ label, value }: { label: string; value: string }) => (
-
+
{label}
{value}
diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx
index 7f1e05291f..5c8ae10a33 100644
--- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx
+++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetRow/AssetRow.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useCallback, useEffect, useMemo, useState } from "react";
+import React from "react";
import clsx from "clsx";
import Image from "next/image";
import Badge from "@mui/material/Badge";
@@ -14,11 +14,9 @@ import {
} from "@mrgnlabs/marginfi-v2-ui-state";
import { MarginfiAccountWrapper, PriceBias } from "@mrgnlabs/marginfi-client-v2";
-import { useMrgnlendStore, useUserProfileStore, useUiStore } from "~/store";
-import { closeBalance, executeLendingAction, MarginfiActionParams, cn } from "~/utils";
+import { useUserProfileStore, useUiStore } from "~/store";
import { LendingModes } from "~/types";
import { useAssetItemData } from "~/hooks/useAssetItemData";
-import { useWalletContext } from "~/hooks/useWalletContext";
import { useIsMobile } from "~/hooks/useIsMobile";
import { MrgnTooltip } from "~/components/common/MrgnTooltip";
@@ -26,6 +24,7 @@ import { AssetRowAction, LSTDialogVariants } from "~/components/common/AssetList
import { ActionBoxDialog } from "~/components/common/ActionBox";
import { Button } from "~/components/ui/button";
import { IconAlertTriangle } from "~/components/ui/icons";
+import { cn } from "~/utils";
export const EMISSION_MINT_INFO_MAP = new Map([
[
@@ -46,7 +45,7 @@ export const EMISSION_MINT_INFO_MAP = new Map {
const [lendZoomLevel, denominationUSD] = useUserProfileStore((state) => [state.lendZoomLevel, state.denominationUSD]);
- const setIsRefreshingStore = useMrgnlendStore((state) => state.setIsRefreshingStore);
- const [mfiClient, fetchMrgnlendState] = useMrgnlendStore((state) => [state.marginfiClient, state.fetchMrgnlendState]);
const [lendingMode, isFilteredUserPositions, setSelectedToken] = useUiStore((state) => [
state.lendingMode,
state.isFilteredUserPositions,
state.setSelectedToken,
]);
const { rateAP, assetWeight, isBankFilled, isBankHigh, bankCap } = useAssetItemData({ bank, isInLendingMode });
- const [hasLSTDialogShown, setHasLSTDialogShown] = useState([]);
- const { walletContextState } = useWalletContext();
const isMobile = useIsMobile();
- const isReduceOnly = useMemo(
+ const isReduceOnly = React.useMemo(
() => (bank?.meta?.tokenSymbol ? REDUCE_ONLY_BANKS.includes(bank.meta.tokenSymbol) : false),
[bank.meta.tokenSymbol]
);
- const isUserPositionPoorHealth = useMemo(() => {
+ const isUserPositionPoorHealth = React.useMemo(() => {
if (!activeBank || !activeBank.position.liquidationPrice) {
return false;
}
@@ -108,7 +103,7 @@ const AssetRow: FC<{
}
}, [activeBank]);
- const userPositionColSpan = useMemo(() => {
+ const userPositionColSpan = React.useMemo(() => {
if (isMobile) {
return 4;
}
@@ -121,13 +116,13 @@ const AssetRow: FC<{
return 9;
}, [isMobile, lendZoomLevel]);
- const assetPrice = useMemo(
+ const assetPrice = React.useMemo(
() =>
bank.info.oraclePrice.priceRealtime ? bank.info.oraclePrice.priceRealtime.toNumber() : bank.info.state.price,
[bank.info.oraclePrice.priceRealtime, bank.info.state.price]
);
- const assetPriceOffset = useMemo(
+ const assetPriceOffset = React.useMemo(
() =>
Math.max(
bank.info.rawBank.getPrice(bank.info.oraclePrice, PriceBias.Highest).toNumber() - bank.info.state.price,
@@ -136,137 +131,13 @@ const AssetRow: FC<{
[bank.info]
);
- const [amount, setAmount] = useState(0);
-
- const currentAction: ActionType = useMemo(() => getCurrentAction(isInLendingMode, bank), [isInLendingMode, bank]);
-
- const maxAmount = useMemo(() => {
- switch (currentAction) {
- case ActionType.Deposit:
- return bank.userInfo.maxDeposit;
- case ActionType.Withdraw:
- return bank.userInfo.maxWithdraw;
- case ActionType.Borrow:
- return bank.userInfo.maxBorrow;
- case ActionType.Repay:
- return bank.userInfo.maxRepay;
- }
- }, [bank, currentAction]);
- const isDust = bank.isActive && bank.position.isDust;
- const showCloseBalance = currentAction === ActionType.Withdraw && isDust; // Only case we should show close balance is when we are withdrawing a dust balance, since user receives 0 tokens back (vs repaying a dust balance where the input box will show the smallest unit of the token)
- const isActionDisabled = maxAmount === 0 && !showCloseBalance;
-
- // Reset b/l amounts on toggle
- useEffect(() => {
- setAmount(0);
- }, [isInLendingMode]);
-
- const handleCloseBalance = useCallback(async () => {
- try {
- await closeBalance({ marginfiAccount, bank });
- } catch (error) {
- return;
- }
-
- setAmount(0);
-
- try {
- setIsRefreshingStore(true);
- await fetchMrgnlendState();
- } catch (error: any) {
- console.log("Error while reloading state");
- console.log(error);
- }
- }, [bank, marginfiAccount, fetchMrgnlendState, setIsRefreshingStore]);
-
- const executeLendingActionCb = useCallback(
- async ({
- mfiClient,
- actionType: currentAction,
- bank,
- amount: borrowOrLendAmount,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- }: MarginfiActionParams) => {
- await executeLendingAction({
- mfiClient,
- actionType: currentAction,
- bank,
- amount: borrowOrLendAmount,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- });
-
- setAmount(0);
-
- // -------- Refresh state
- try {
- setIsRefreshingStore(true);
- await fetchMrgnlendState();
- } catch (error: any) {
- console.log("Error while reloading state");
- console.log(error);
- }
- },
- [fetchMrgnlendState, setIsRefreshingStore]
+ const currentAction: ActionType = React.useMemo(
+ () => getCurrentAction(isInLendingMode, bank),
+ [isInLendingMode, bank]
);
- const handleLendingAction = useCallback(async () => {
- if (
- currentAction === ActionType.Deposit &&
- (bank.meta.tokenSymbol === "SOL" || bank.meta.tokenSymbol === "stSOL") &&
- !hasLSTDialogShown.includes(bank.meta.tokenSymbol as LSTDialogVariants) &&
- showLSTDialog
- ) {
- setHasLSTDialogShown((prev) => [...prev, bank.meta.tokenSymbol as LSTDialogVariants]);
- showLSTDialog(bank.meta.tokenSymbol as LSTDialogVariants, async () => {
- await executeLendingActionCb({
- mfiClient,
- actionType: currentAction,
- bank,
- amount: amount,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- });
- });
- return;
- }
-
- await executeLendingActionCb({
- mfiClient,
- actionType: currentAction,
- bank,
- amount: amount,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- });
-
- if (
- currentAction === ActionType.Withdraw &&
- (bank.meta.tokenSymbol === "SOL" || bank.meta.tokenSymbol === "stSOL") &&
- !hasLSTDialogShown.includes(bank.meta.tokenSymbol as LSTDialogVariants) &&
- showLSTDialog
- ) {
- setHasLSTDialogShown((prev) => [...prev, bank.meta.tokenSymbol as LSTDialogVariants]);
- showLSTDialog(bank.meta.tokenSymbol as LSTDialogVariants);
- return;
- }
- }, [
- currentAction,
- bank,
- hasLSTDialogShown,
- showLSTDialog,
- executeLendingActionCb,
- mfiClient,
- amount,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- ]);
+ const isDust = React.useMemo(() => bank.isActive && bank.position.isDust, [bank]);
+ const showCloseBalance = currentAction === ActionType.Withdraw && isDust; // Only case we should show close balance is when we are withdrawing a dust balance, since user receives 0 tokens back (vs repaying a dust balance where the input box will show the smallest unit of the token)
return (
<>
@@ -597,7 +468,7 @@ const AssetRow: FC<{
);
};
-const LoadingAsset: FC<{ isInLendingMode: boolean; bankMetadata: ExtendedBankMetadata }> = ({
+const LoadingAsset: React.FC<{ isInLendingMode: boolean; bankMetadata: ExtendedBankMetadata }> = ({
isInLendingMode,
bankMetadata,
}) => (
diff --git a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx
index e7294ef3c3..b337e0c72e 100644
--- a/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx
+++ b/apps/marginfi-v2-ui/src/components/desktop/AssetsList/AssetsList.tsx
@@ -191,7 +191,7 @@ const AssetsList = () => {
{poolFilter !== "isolated" && (
<>
-
+
Global pool
{
- {globalBanks
- .filter((b) => !b.info.state.isIsolated)
- .map((bank, i) => {
+ {globalBanks.length ? (
+ globalBanks.map((bank, i) => {
if (poolFilter === "stable" && !STABLECOINS.includes(bank.meta.tokenSymbol)) return null;
if (poolFilter === "lst" && !LSTS.includes(bank.meta.tokenSymbol)) return null;
@@ -247,14 +246,21 @@ const AssetsList = () => {
bankMetadata={bank.meta}
/>
);
- })}
+ })
+ ) : (
+
+
+ No global banks found.
+
+
+ )}
>
)}
{poolFilter !== "stable" && poolFilter !== "lst" && (
<>
-
+
Isolated pools
@@ -280,9 +286,8 @@ const AssetsList = () => {
- {isolatedBanks
- .filter((b) => b.info.state.isIsolated)
- .map((bank) => {
+ {isolatedBanks.length ? (
+ isolatedBanks.map((bank) => {
const activeBank = activeBankInfos.filter(
(activeBankInfo) => activeBankInfo.meta.tokenSymbol === bank.meta.tokenSymbol
);
@@ -308,7 +313,14 @@ const AssetsList = () => {
bankMetadata={bank.meta}
/>
);
- })}
+ })
+ ) : (
+
+
+ No isolated banks found.
+
+
+ )}
>
diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx
index cb121670f7..4bc5ea7fe0 100644
--- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx
+++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCard.tsx
@@ -1,37 +1,29 @@
-import React, { FC, useCallback, useMemo, useState } from "react";
+import React, { FC, useMemo } from "react";
import { WSOL_MINT } from "@mrgnlabs/mrgn-common";
import { ExtendedBankInfo, ActiveBankInfo, ActionType, getCurrentAction } from "@mrgnlabs/marginfi-v2-ui-state";
-import { MarginfiAccountWrapper } from "@mrgnlabs/marginfi-client-v2";
-import { useMrgnlendStore, useUiStore } from "~/store";
-import { executeLendingAction, closeBalance, MarginfiActionParams } from "~/utils";
+
+import { useUiStore } from "~/store";
+import { LendingModes } from "~/types";
+
import { useAssetItemData } from "~/hooks/useAssetItemData";
-import { useWalletContext } from "~/hooks/useWalletContext";
import { LSTDialogVariants } from "~/components/common/AssetList";
+
import { AssetCardStats } from "./AssetCardStats";
import { AssetCardActions } from "./AssetCardActions";
import { AssetCardPosition } from "./AssetCardPosition";
import { AssetCardHeader } from "./AssetCardHeader";
-import { LendingModes } from "~/types";
export const AssetCard: FC<{
bank: ExtendedBankInfo;
activeBank?: ActiveBankInfo;
nativeSolBalance: number;
isInLendingMode: boolean;
- isConnected: boolean;
- marginfiAccount: MarginfiAccountWrapper | null;
- inputRefs?: React.MutableRefObject
>;
- showLSTDialog?: (variant: LSTDialogVariants, callback?: () => void) => void;
-}> = ({ bank, activeBank, nativeSolBalance, isInLendingMode, marginfiAccount, inputRefs, showLSTDialog }) => {
+}> = ({ bank, activeBank, nativeSolBalance, isInLendingMode }) => {
const { rateAP, assetWeight, isBankFilled, isBankHigh, bankCap } = useAssetItemData({ bank, isInLendingMode });
- const [mfiClient, fetchMrgnlendState] = useMrgnlendStore((state) => [state.marginfiClient, state.fetchMrgnlendState]);
- const setIsRefreshingStore = useMrgnlendStore((state) => state.setIsRefreshingStore);
const [lendingMode, isFilteredUserPositions] = useUiStore((state) => [
state.lendingMode,
state.isFilteredUserPositions,
]);
- const [hasLSTDialogShown, setHasLSTDialogShown] = useState([]);
- const { walletContextState } = useWalletContext();
const totalDepositsOrBorrows = useMemo(
() =>
@@ -54,111 +46,6 @@ export const AssetCard: FC<{
const currentAction: ActionType = useMemo(() => getCurrentAction(isInLendingMode, bank), [isInLendingMode, bank]);
- const handleCloseBalance = useCallback(async () => {
- try {
- await closeBalance({ marginfiAccount, bank });
- } catch (error) {
- return;
- }
-
- try {
- setIsRefreshingStore(true);
- await fetchMrgnlendState();
- } catch (error: any) {
- console.log("Error while reloading state");
- console.log(error);
- }
- }, [bank, marginfiAccount, fetchMrgnlendState, setIsRefreshingStore]);
-
- const executeLendingActionCb = useCallback(
- async (
- amount: number,
- {
- mfiClient,
- actionType: currentAction,
- bank,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- }: Omit
- ) => {
- await executeLendingAction({
- mfiClient,
- actionType: currentAction,
- bank,
- amount,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- });
-
- // -------- Refresh state
- try {
- setIsRefreshingStore(true);
- await fetchMrgnlendState();
- } catch (error: any) {
- console.log("Error while reloading state");
- console.log(error);
- }
- },
- [fetchMrgnlendState, setIsRefreshingStore]
- );
-
- const handleLendingAction = useCallback(
- async (borrowOrLendAmount: number) => {
- if (
- currentAction === ActionType.Deposit &&
- (bank.meta.tokenSymbol === "SOL" || bank.meta.tokenSymbol === "stSOL") &&
- !hasLSTDialogShown.includes(bank.meta.tokenSymbol as LSTDialogVariants) &&
- showLSTDialog
- ) {
- setHasLSTDialogShown((prev) => [...prev, bank.meta.tokenSymbol as LSTDialogVariants]);
- showLSTDialog(bank.meta.tokenSymbol as LSTDialogVariants, async () => {
- await executeLendingActionCb(borrowOrLendAmount, {
- mfiClient,
- actionType: currentAction,
- bank,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- });
- });
- return;
- }
-
- await executeLendingActionCb(borrowOrLendAmount, {
- mfiClient,
- actionType: currentAction,
- bank,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- });
-
- if (
- currentAction === ActionType.Withdraw &&
- (bank.meta.tokenSymbol === "SOL" || bank.meta.tokenSymbol === "stSOL") &&
- !hasLSTDialogShown.includes(bank.meta.tokenSymbol as LSTDialogVariants) &&
- showLSTDialog
- ) {
- setHasLSTDialogShown((prev) => [...prev, bank.meta.tokenSymbol as LSTDialogVariants]);
- showLSTDialog(bank.meta.tokenSymbol as LSTDialogVariants);
- return;
- }
- },
- [
- currentAction,
- bank,
- hasLSTDialogShown,
- showLSTDialog,
- executeLendingActionCb,
- mfiClient,
- nativeSolBalance,
- marginfiAccount,
- walletContextState,
- ]
- );
-
return (
)}
-
+
);
};
diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardActions.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardActions.tsx
index 5370b86aa0..75beb9fe14 100644
--- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardActions.tsx
+++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/AssetCard/AssetCardActions.tsx
@@ -1,70 +1,38 @@
import React, { FC, useMemo, useState } from "react";
import { ExtendedBankInfo, ActionType } from "@mrgnlabs/marginfi-v2-ui-state";
-import { uiToNative } from "@mrgnlabs/mrgn-common";
+
import { AssetRowAction, AssetRowInputBox } from "~/components/common/AssetList";
+import { ActionBoxDialog } from "~/components/common/ActionBox";
+import { useUiStore } from "~/store";
export const AssetCardActions: FC<{
bank: ExtendedBankInfo;
- isBankFilled: boolean;
- isInLendingMode: boolean;
currentAction: ActionType;
- inputRefs?: React.MutableRefObject
>;
- onCloseBalance: () => void;
- onBorrowOrLend: (amount: number) => void;
-}> = ({ bank, inputRefs, currentAction, onCloseBalance, onBorrowOrLend }) => {
- const [borrowOrLendAmount, setBorrowOrLendAmount] = useState(0);
-
- const maxAmount = useMemo(() => {
- switch (currentAction) {
- case ActionType.Deposit:
- return bank.userInfo.maxDeposit;
- case ActionType.Withdraw:
- return bank.userInfo.maxWithdraw;
- case ActionType.Borrow:
- return bank.userInfo.maxBorrow;
- case ActionType.Repay:
- return bank.userInfo.maxRepay;
- }
- }, [bank.userInfo, currentAction]);
+}> = ({ bank, currentAction }) => {
+ const [setSelectedToken] = useUiStore((state) => [state.setSelectedToken]);
- const isDust = useMemo(
- () => bank.isActive && uiToNative(bank.position.amount, bank.info.state.mintDecimals).isZero(),
- [bank]
- );
-
- const isDisabled = useMemo(
- () =>
- (isDust &&
- uiToNative(bank.userInfo.tokenAccount.balance, bank.info.state.mintDecimals).isZero() &&
- currentAction == ActionType.Borrow) ||
- (!isDust && maxAmount === 0),
- [currentAction, bank, isDust, maxAmount]
- );
+ const isDust = React.useMemo(() => bank.isActive && bank.position.isDust, [bank]);
+ const showCloseBalance = React.useMemo(
+ () => currentAction === ActionType.Withdraw && isDust,
+ [currentAction, isDust]
+ ); // Only case we should show close balance is when we are withdrawing a dust balance, since user receives 0 tokens back (vs repaying a dust balance where the input box will show the smallest unit of the token)
return (
<>
-
onBorrowOrLend(borrowOrLendAmount)}
- />
- (isDust ? onCloseBalance() : onBorrowOrLend(borrowOrLendAmount))}
- disabled={isDisabled}
- >
- {isDust ? "Close" : currentAction}
-
+
+ setSelectedToken(bank)}
+ >
+ {showCloseBalance ? "Close" : currentAction}
+
+
>
);
diff --git a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx
index d6bffb3d5c..9f6be0b96f 100644
--- a/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx
+++ b/apps/marginfi-v2-ui/src/components/mobile/MobileAssetsList/MobileAssetsList.tsx
@@ -6,7 +6,6 @@ import { ExtendedBankInfo, ActiveBankInfo } from "@mrgnlabs/marginfi-v2-ui-state
import { Skeleton, Typography } from "@mui/material";
import { useMrgnlendStore, useUiStore } from "~/store";
-import { useWalletContext } from "~/hooks/useWalletContext";
import { MrgnTooltip } from "~/components/common";
import {
@@ -20,19 +19,21 @@ import {
} from "~/components/common/AssetList";
import { AssetCard } from "~/components/mobile/MobileAssetsList/AssetCard";
-import { LendingModes } from "~/types";
+import { LendingModes, UserMode } from "~/types";
+import { useWalletContext } from "~/hooks/useWalletContext";
+import { Portfolio } from "~/components/common/Portfolio";
export const MobileAssetsList = () => {
- const { connected } = useWalletContext();
+ const { connected, walletAddress } = useWalletContext();
- const [isStoreInitialized, extendedBankInfos, nativeSolBalance, selectedAccount] = useMrgnlendStore((state) => [
+ const [isStoreInitialized, extendedBankInfos, nativeSolBalance] = useMrgnlendStore((state) => [
state.initialized,
state.extendedBankInfos,
state.nativeSolBalance,
- state.selectedAccount,
]);
- const [lendingMode, isFilteredUserPositions, sortOption, poolFilter] = useUiStore((state) => [
+ const [userMode, lendingMode, isFilteredUserPositions, sortOption, poolFilter] = useUiStore((state) => [
+ state.userMode,
state.lendingMode,
state.isFilteredUserPositions,
state.sortOption,
@@ -40,7 +41,6 @@ export const MobileAssetsList = () => {
]);
const isInLendingMode = React.useMemo(() => lendingMode === LendingModes.LEND, [lendingMode]);
- const inputRefs = React.useRef>({});
const [isLSTDialogOpen, setIsLSTDialogOpen] = React.useState(false);
const [lstDialogVariant, setLSTDialogVariant] = React.useState(null);
const [lstDialogCallback, setLSTDialogCallback] = React.useState<(() => void) | null>(null);
@@ -94,128 +94,118 @@ export const MobileAssetsList = () => {
return (
<>
-
- {poolFilter !== "isolated" && (
-
-
- Global pool
-
- {isStoreInitialized && globalBanks ? (
- globalBanks.length > 0 ? (
-
- {globalBanks.map((bank) => {
- if (poolFilter === "stable" && !STABLECOINS.includes(bank.meta.tokenSymbol)) return null;
- if (poolFilter === "lst" && !LSTS.includes(bank.meta.tokenSymbol)) return null;
-
- const activeBank = activeBankInfos.filter(
- (activeBankInfo) => activeBankInfo.meta.tokenSymbol === bank.meta.tokenSymbol
- );
-
- return (
-
void) => {
- setLSTDialogVariant(variant);
- setIsLSTDialogOpen(true);
- if (onClose) {
- setLSTDialogCallback(() => onClose);
- }
- }}
- />
- );
- })}
-
+ {userMode === UserMode.PRO && (
+
+ {poolFilter !== "isolated" && (
+
+
+ Global pool
+
+ {isStoreInitialized && globalBanks ? (
+ globalBanks.length > 0 ? (
+
+ {globalBanks.map((bank) => {
+ if (poolFilter === "stable" && !STABLECOINS.includes(bank.meta.tokenSymbol)) return null;
+ if (poolFilter === "lst" && !LSTS.includes(bank.meta.tokenSymbol)) return null;
+
+ const activeBank = activeBankInfos.filter(
+ (activeBankInfo) => activeBankInfo.meta.tokenSymbol === bank.meta.tokenSymbol
+ );
+
+ return (
+
+ );
+ })}
+
+ ) : (
+
+ No {isInLendingMode ? "lending" : "borrowing"} {isFilteredUserPositions ? "positions" : "pools"}{" "}
+ found.
+
+ )
) : (
-
- No {isInLendingMode ? "lending" : "borrowing"} {isFilteredUserPositions ? "positions" : "pools"}{" "}
- found.
-
- )
- ) : (
-
- {[...Array(6)].map((_, i) => (
-
- ))}
-
- )}
-
- )}
- {poolFilter !== "stable" && poolFilter !== "lst" && (
-
-
- Isolated pools
-
-
- Isolated pools are risky ⚠️
-
- Assets in isolated pools cannot be used as collateral. When you borrow an isolated asset, you cannot
- borrow other assets. Isolated pools should be considered particularly risky. As always, remember
- that marginfi is a decentralized protocol and all deposited funds are at risk.
- >
- }
- placement="top"
- >
-
-
-
-
- {isStoreInitialized && globalBanks ? (
- isolatedBanks.length > 0 ? (
-
- {isolatedBanks.map((bank, i) => {
- const activeBank = activeBankInfos.filter(
- (activeBankInfo) => activeBankInfo.meta.tokenSymbol === bank.meta.tokenSymbol
- );
-
- return (
-
- );
- })}
+
+ {[...Array(6)].map((_, i) => (
+
+ ))}
+ )}
+
+ )}
+ {poolFilter !== "stable" && poolFilter !== "lst" && (
+
+
+ Isolated pools
+
+
+ Isolated pools are risky ⚠️
+
+ Assets in isolated pools cannot be used as collateral. When you borrow an isolated asset, you
+ cannot borrow other assets. Isolated pools should be considered particularly risky. As always,
+ remember that marginfi is a decentralized protocol and all deposited funds are at risk.
+ >
+ }
+ placement="top"
+ >
+
+
+
+
+ {isStoreInitialized && globalBanks ? (
+ isolatedBanks.length > 0 ? (
+
+ {isolatedBanks.map((bank, i) => {
+ const activeBank = activeBankInfos.filter(
+ (activeBankInfo) => activeBankInfo.meta.tokenSymbol === bank.meta.tokenSymbol
+ );
+
+ return (
+
+ );
+ })}
+
+ ) : (
+
+ No {isInLendingMode ? "lending" : "borrowing"} {isFilteredUserPositions ? "positions" : "pools"}{" "}
+ found.
+
+ )
) : (
-
- No {isInLendingMode ? "lending" : "borrowing"} {isFilteredUserPositions ? "positions" : "pools"}{" "}
- found.
-
- )
- ) : (
-
- {[...Array(6)].map((_, i) => (
-
- ))}
-
- )}
-
- )}
-
+
+ {[...Array(6)].map((_, i) => (
+
+ ))}
+
+ )}
+
+ )}
+
+ )}
+ {walletAddress &&
}
{
-
+ {/*
*/}
{!connected ? null : currentFirebaseUser ? (
) : hasUser === null ? (
@@ -167,8 +167,6 @@ const PortfolioPage = () => {
nativeSolBalance={nativeSolBalance}
bank={bank}
isInLendingMode={true}
- isConnected={connected}
- marginfiAccount={selectedAccount}
/>
))}
@@ -198,8 +196,6 @@ const PortfolioPage = () => {
nativeSolBalance={nativeSolBalance}
bank={bank}
isInLendingMode={false}
- isConnected={connected}
- marginfiAccount={selectedAccount}
/>
))}
diff --git a/packages/marginfi-client-v2/src/models/account/pure.ts b/packages/marginfi-client-v2/src/models/account/pure.ts
index 16315cd88c..f23f794055 100644
--- a/packages/marginfi-client-v2/src/models/account/pure.ts
+++ b/packages/marginfi-client-v2/src/models/account/pure.ts
@@ -349,6 +349,43 @@ class MarginfiAccount {
}
}
+ /**
+ * Calculate the price at which the user position for the given bank and amount will lead to liquidation, all other prices constant.
+ */
+ public computeLiquidationPriceForBankAmount(
+ banks: Map,
+ oraclePrices: Map,
+ bankAddress: PublicKey,
+ isLending: boolean,
+ amount: number,
+ ): number | null {
+ const bank = banks.get(bankAddress.toBase58());
+ if (!bank) throw Error(`Bank ${bankAddress.toBase58()} not found`);
+ const priceInfo = oraclePrices.get(bankAddress.toBase58());
+ if (!priceInfo) throw Error(`Price info for ${bankAddress.toBase58()} not found`);
+
+ const balance = this.getBalance(bankAddress);
+
+ if (!balance.active) return null;
+
+ const { assets, liabilities } = this.computeHealthComponents(banks, oraclePrices, MarginRequirementType.Maintenance, [bankAddress]);
+ const amountBn = new BigNumber(amount)
+
+ if (isLending) {
+ if (liabilities.eq(0)) return null;
+
+ const assetWeight = bank.getAssetWeight(MarginRequirementType.Maintenance);
+ const priceConfidence = bank.getPrice(priceInfo, PriceBias.None).minus(bank.getPrice(priceInfo, PriceBias.Lowest));
+ const liquidationPrice = liabilities.minus(assets).div(amountBn.times(assetWeight)).plus(priceConfidence);
+ return liquidationPrice.toNumber();
+ } else {
+ const liabWeight = bank.getLiabilityWeight(MarginRequirementType.Maintenance);
+ const priceConfidence = bank.getPrice(priceInfo, PriceBias.Highest).minus(bank.getPrice(priceInfo, PriceBias.None));
+ const liquidationPrice = assets.minus(liabilities).div(amountBn.times(liabWeight)).minus(priceConfidence);
+ return liquidationPrice.toNumber();
+ }
+ }
+
// Calculate the max amount of collateral to liquidate to bring an account maint health to 0 (assuming negative health).
//
// The asset amount is bounded by 2 constraints,
diff --git a/packages/marginfi-client-v2/src/models/account/wrapper.ts b/packages/marginfi-client-v2/src/models/account/wrapper.ts
index 0251178524..3ec961fa9c 100644
--- a/packages/marginfi-client-v2/src/models/account/wrapper.ts
+++ b/packages/marginfi-client-v2/src/models/account/wrapper.ts
@@ -166,6 +166,15 @@ class MarginfiAccountWrapper {
return this._marginfiAccount.computeLiquidationPriceForBank(this.client.banks, this.client.oraclePrices, bankAddress);
}
+ public computeLiquidationPriceForBankAmount(
+ bankAddress: PublicKey,
+ isLending: boolean,
+ amount: number
+ ): number | null {
+ return this._marginfiAccount.computeLiquidationPriceForBankAmount(this.client.banks, this.client.oraclePrices, bankAddress, isLending, amount);
+ }
+
+
public computeNetApy(): number {
return this._marginfiAccount.computeNetApy(this.client.banks, this.client.oraclePrices);
}