diff --git a/apps/marginfi-v2-xnft/App.tsx b/apps/marginfi-v2-xnft/App.tsx
index 8b3921580b..d0f0da9d87 100644
--- a/apps/marginfi-v2-xnft/App.tsx
+++ b/apps/marginfi-v2-xnft/App.tsx
@@ -16,6 +16,7 @@ import { SwapContextProvider } from "~/context";
import { useConnection } from "~/hooks/useConnection";
import { useWallet } from "~/hooks/useWallet";
import { ROUTE_CACHE_DURATION } from "~/consts";
+import { PieChartIcon, ReceiveMoneyIcon, TokenSwapIcon } from "~/assets/icons";
require("~/styles/globals.css");
require("~/styles/fonts.css");
@@ -82,7 +83,7 @@ function TabNavigator() {
options={{
header: (props: BottomTabHeaderProps) => ,
tabBarLabel: "Lend",
- tabBarIcon: ({ color, size }) => ,
+ tabBarIcon: ({ color, size }) => ,
}}
/>
,
tabBarLabel: "Swap",
- tabBarIcon: ({ color, size }) => ,
+ tabBarIcon: ({ color, size }) => ,
}}
/>
,
tabBarLabel: "Portfolio",
- tabBarIcon: ({ color, size }) => ,
+ tabBarIcon: ({ color, size }) => ,
}}
/>
diff --git a/apps/marginfi-v2-xnft/src/assets/icons/PieChartIcon.tsx b/apps/marginfi-v2-xnft/src/assets/icons/PieChartIcon.tsx
new file mode 100644
index 0000000000..7d3c16a0e3
--- /dev/null
+++ b/apps/marginfi-v2-xnft/src/assets/icons/PieChartIcon.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+
+interface PieChartIconProps extends React.SVGAttributes {
+ color?: string;
+}
+
+export const PieChartIcon: React.FC = ({ width = "24", height = "24", color = "white" }) => {
+ return (
+
+ );
+};
diff --git a/apps/marginfi-v2-xnft/src/assets/icons/ReceiveMoneyIcon.tsx b/apps/marginfi-v2-xnft/src/assets/icons/ReceiveMoneyIcon.tsx
new file mode 100644
index 0000000000..763a18e82a
--- /dev/null
+++ b/apps/marginfi-v2-xnft/src/assets/icons/ReceiveMoneyIcon.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+interface ReceiveMoneyIconProps extends React.SVGAttributes {
+ color?: string;
+}
+
+export const ReceiveMoneyIcon: React.FC = ({ width = "24", height = "24", color = "black" }) => {
+ return (
+
+ );
+};
diff --git a/apps/marginfi-v2-xnft/src/assets/icons/TokenSwapIcon.tsx b/apps/marginfi-v2-xnft/src/assets/icons/TokenSwapIcon.tsx
new file mode 100644
index 0000000000..c83464147a
--- /dev/null
+++ b/apps/marginfi-v2-xnft/src/assets/icons/TokenSwapIcon.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+
+interface TokenSwapIconProps extends React.SVGAttributes {
+ color?: string;
+}
+
+export const TokenSwapIcon: React.FC = ({ width = "24", height = "24", color = "black" }) => {
+ return (
+
+ );
+};
diff --git a/apps/marginfi-v2-xnft/src/assets/icons/chevron-down.svg b/apps/marginfi-v2-xnft/src/assets/icons/chevron-down.svg
deleted file mode 100644
index 1b95cdaf65..0000000000
--- a/apps/marginfi-v2-xnft/src/assets/icons/chevron-down.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/apps/marginfi-v2-xnft/src/assets/icons/index.ts b/apps/marginfi-v2-xnft/src/assets/icons/index.ts
index 36e9e1618e..abd3687121 100644
--- a/apps/marginfi-v2-xnft/src/assets/icons/index.ts
+++ b/apps/marginfi-v2-xnft/src/assets/icons/index.ts
@@ -11,3 +11,6 @@ export * from "./RefreshIcon";
export * from "./SettingsIcon";
export * from "./CloseIcon";
export * from "./ErrorIcon";
+export * from "./PieChartIcon";
+export * from "./ReceiveMoneyIcon";
+export * from "./TokenSwapIcon";
diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx
index 69b6e95bfc..88a72cff52 100644
--- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx
+++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCard.tsx
@@ -7,7 +7,7 @@ import { MarginfiAccountWrapper, MarginfiClient } from "@mrgnlabs/marginfi-clien
import { PoolCardPosition } from "./PoolCardPosition";
import { useConnection } from "~/hooks/useConnection";
import { ActionType, Emissions, ExtendedBankInfo, FEE_MARGIN, getCurrentAction } from "@mrgnlabs/marginfi-v2-ui-state";
-import { showErrorToast } from "~/utils";
+import { showErrorToast, showSuccessToast } from "~/utils";
import { percentFormatter, usdFormatter } from "@mrgnlabs/mrgn-common";
type Props = {
@@ -120,6 +120,8 @@ export function PoolCard({
const withdrawAll = bankInfo.isActive ? borrowOrLendAmount === bankInfo.position.amount : false;
await _marginfiAccount.withdraw(borrowOrLendAmount, bankInfo.address, withdrawAll);
}
+
+ showSuccessToast(`${currentAction + "ing"} ${borrowOrLendAmount} ${bankInfo.meta.tokenSymbol} 👍`);
} catch (error: any) {
console.log(`Error while ${currentAction + "ing"}`);
console.log(error);
@@ -136,8 +138,46 @@ export function PoolCard({
[bankInfo, connection, currentAction, marginfiAccount, marginfiClient, nativeSolBalance, reloadBanks]
);
+ const closeBalance = useCallback(async () => {
+ if (!marginfiAccount) {
+ showErrorToast("marginfi account not ready.");
+ return;
+ }
+
+ if (!bankInfo.isActive) {
+ showErrorToast("no position to close.");
+ return;
+ }
+
+ try {
+ if (bankInfo.position.isLending) {
+ await marginfiAccount.withdraw(0, bankInfo.address, true);
+ } else {
+ await marginfiAccount.repay(0, bankInfo.address, true);
+ }
+ showSuccessToast("Closing 👍");
+ } catch (error: any) {
+ showSuccessToast(`Error while closing balance: ${error.message}`);
+ console.log(`Error while closing balance`);
+ console.log(error);
+ }
+
+ // TODO: set values back to 0
+ try {
+ await reloadBanks();
+ } catch (error: any) {
+ console.log("Error while reloading state");
+ console.log(error);
+ }
+ }, [bankInfo, marginfiAccount, reloadBanks]);
+
return (
-
+
@@ -163,7 +203,7 @@ export function PoolCard({
currentAction={currentAction}
isBankFilled={isInLendingMode ? depositFilled >= 0.9999 : borrowFilled >= 0.9999}
bank={bankInfo}
- onAction={(amount) => borrowOrLend(amount)}
+ onAction={(amount) => (amount ? borrowOrLend(amount) : closeBalance())}
/>
);
diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardActions.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardActions.tsx
index 4546412ead..d2671d033f 100644
--- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardActions.tsx
+++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardActions.tsx
@@ -3,12 +3,13 @@ import { View, Text, Pressable } from "react-native";
import tw from "~/styles/tailwind";
import { NumberInput, PrimaryButton, SecondaryButton } from "~/components/Common";
import { ActionType, ExtendedBankInfo } from "@mrgnlabs/marginfi-v2-ui-state";
+import { uiToNative } from "@mrgnlabs/mrgn-common";
type Props = {
currentAction: ActionType;
bank: ExtendedBankInfo;
isBankFilled: boolean;
- onAction: (amount: string) => void;
+ onAction: (amount?: string) => void;
};
export function PoolCardActions({ currentAction, bank, isBankFilled, onAction }: Props) {
@@ -27,20 +28,20 @@ export function PoolCardActions({ currentAction, bank, isBankFilled, onAction }:
}
}, [bank.userInfo, currentAction]);
- const isDisabled = useMemo(() => {
- switch (currentAction) {
- case ActionType.Deposit:
- return isBankFilled;
- case ActionType.Withdraw:
- return false;
- case ActionType.Borrow:
- return isBankFilled;
- case ActionType.Repay:
- return false;
- }
- }, [currentAction, isBankFilled]);
+ 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()) ||
+ maxAmount === 0,
+ [currentAction, bank, isDust, maxAmount]
+ );
const buttonText = useMemo(() => {
+ if (isDust) return "Close";
switch (currentAction) {
case ActionType.Deposit:
return isDisabled ? "Deposits reached the limit" : "Supply";
@@ -51,7 +52,7 @@ export function PoolCardActions({ currentAction, bank, isBankFilled, onAction }:
case ActionType.Repay:
return "Repay";
}
- }, [currentAction, isDisabled]);
+ }, [currentAction, isDisabled, isDust]);
return (
<>
@@ -72,7 +73,7 @@ export function PoolCardActions({ currentAction, bank, isBankFilled, onAction }:
{currentAction == ActionType.Withdraw || currentAction == ActionType.Repay ? (
- onAction(amount)} />
+ (isDust ? onAction() : onAction(amount))} />
) : (
onAction(amount)} />
)}
diff --git a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardSkeleton.tsx b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardSkeleton.tsx
index ca9d8e9a53..cae35f07d7 100644
--- a/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardSkeleton.tsx
+++ b/apps/marginfi-v2-xnft/src/components/Lend/PoolCard/PoolCardSkeleton.tsx
@@ -4,7 +4,7 @@ import { View } from "react-native";
import tw from "~/styles/tailwind";
export const PoolCardSkeleton = (props?: JSX.IntrinsicAttributes & IContentLoaderProps) => (
-
+
bankFilled >= 0.9, [bankFilled]);
return (
-
+
Weight
{assetWeight}
diff --git a/apps/marginfi-v2-xnft/src/screens/LendScreen.tsx b/apps/marginfi-v2-xnft/src/screens/LendScreen.tsx
index 7b95940b21..f8c4b18714 100644
--- a/apps/marginfi-v2-xnft/src/screens/LendScreen.tsx
+++ b/apps/marginfi-v2-xnft/src/screens/LendScreen.tsx
@@ -68,52 +68,56 @@ export function LendScreen() {
Filter my positions
Global pools
- {extendedBankInfos.length > 0 ? (
- globalPools.length > 0 ? (
- globalPools.map((extendedBankInfo, idx) => (
- {
- if (!connection) return;
- fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet });
- }}
- marginfiClient={marginfiClient}
- >
- ))
+
+ {extendedBankInfos.length > 0 ? (
+ globalPools.length > 0 ? (
+ globalPools.map((extendedBankInfo, idx) => (
+ {
+ if (!connection) return;
+ fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet });
+ }}
+ marginfiClient={marginfiClient}
+ >
+ ))
+ ) : (
+ No Global Pools Found
+ )
) : (
- No Global Pools Found
- )
- ) : (
-
- )}
+
+ )}
+
Isolated pools
- {extendedBankInfos.length > 0 ? (
- isolatedPools.length > 0 ? (
- isolatedPools.map((extendedBankInfo, idx) => (
- {
- if (!connection) return;
- fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet });
- }}
- marginfiClient={marginfiClient}
- >
- ))
+
+ {extendedBankInfos.length > 0 ? (
+ isolatedPools.length > 0 ? (
+ isolatedPools.map((extendedBankInfo, idx) => (
+ {
+ if (!connection) return;
+ fetchMrgnlendState({ marginfiConfig: config.mfiConfig, connection, wallet });
+ }}
+ marginfiClient={marginfiClient}
+ >
+ ))
+ ) : (
+ No Isolated Pools Found
+ )
) : (
- No Isolated Pools Found
- )
- ) : (
-
- )}
+
+ )}
+