Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mfi-v2-ui): improved stake page & stake box #906

Merged
merged 31 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
84874a4
feat: initial structure
borcherd Oct 9, 2024
df985a0
feat: UI with mocked values
borcherd Oct 10, 2024
08bddeb
chore: little work
borcherd Oct 11, 2024
985de1d
feat: tx builder & simulation
borcherd Oct 15, 2024
cb207fb
feat: refactoring & unstake functionality wip
borcherd Oct 16, 2024
8ef9360
feat: stake transaction debugging
borcherd Oct 16, 2024
52c99b2
fix: handleling empty marginfi account
k0beLeenders Oct 16, 2024
0256d6a
cleanup and added update boolean to lst data
k0beLeenders Oct 16, 2024
3a5d289
feat: refactoring, error handling and loading states
borcherd Oct 16, 2024
1be22f6
feat: refactoring
borcherd Oct 17, 2024
d14e896
feat: stakebox context for lstData, receiveAmount calculation
borcherd Oct 17, 2024
96cb952
chore: QA changes
borcherd Oct 17, 2024
ec6ee28
chore: QQ changes
borcherd Oct 17, 2024
e51905a
fix: GH build error
borcherd Oct 17, 2024
6b7a28b
chore: filter out LST
borcherd Oct 18, 2024
2b98812
fix: lst amount & clear on unmount
borcherd Oct 18, 2024
a73481e
chore: suggestion error message handle
k0beLeenders Oct 18, 2024
7078649
chore: error handling
borcherd Oct 18, 2024
17d1c7f
chore: add in error logger to sentry
borcherd Oct 18, 2024
0e082bd
chore: GH QA comment fixes
borcherd Oct 19, 2024
ba75ed0
chore: remove unused error types
borcherd Oct 19, 2024
70fbf12
chore: make useStakeSimulation hook return a function
borcherd Oct 19, 2024
97e271b
fix: only check quote if token needs to be swapped
borcherd Oct 19, 2024
8ea14c3
chore: proper error handling for simulation
borcherd Oct 19, 2024
b184794
chore: fix build failing
k0beLeenders Oct 19, 2024
5bed2ec
feat: added unwrapping sol to lst stake and remove bundleTIpIX
k0beLeenders Oct 19, 2024
1f2698e
chore: toast updates
borcherd Oct 20, 2024
a3d8609
chore: remove selectedAccount check & updated multistep toast msging
borcherd Oct 21, 2024
18753d8
chore: more error handling
borcherd Oct 21, 2024
f439fe7
chore: change titles, change toast pl and toast labels
borcherd Oct 21, 2024
53a486e
minor cleanup
k0beLeenders Oct 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions apps/marginfi-v2-ui/src/components/common/ActionBox/ActionBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -552,19 +552,20 @@ export const ActionBox = ({
});
}

const txnSig = await executeLstAction({
actionMode,
marginfiClient: mfiClient,
amount,
connection,
wallet,
lstData,
bank: selectedBank,
nativeSolBalance,
selectedStakingAccount,
quoteResponseMeta: lstQuoteMeta as any, // TODO: fix type
priorityFee,
});
// const txnSig = await executeLstAction({
// actionMode,
// marginfiClient: mfiClient,
// amount,
// connection,
// wallet,
// lstData,
// bank: selectedBank,
// nativeSolBalance,
// selectedStakingAccount,
// quoteResponseMeta: lstQuoteMeta as any, // TODO: fix type
// priorityFee,
// }); // TODO: This was causing build errors but since this is deprecated code I've commented it out
let txnSig = "";

console.log("executer loop action");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { IconCheck, IconBell } from "@tabler/icons-react";

import { MintCardProps } from "~/utils";
import { useMrgnlendStore } from "~/store";
import { ActionBox } from "@mrgnlabs/mrgn-ui";
import { capture } from "@mrgnlabs/mrgn-utils";

import { Button } from "~/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { ActionBoxDialog } from "~/components/common/ActionBox";
import { LST_MINT } from "~/store/lstStore";
import { useWallet } from "~/components/wallet-v2/hooks/use-wallet.hook";

interface MintCardWrapperProps {
mintCard: MintCardProps;
Expand All @@ -19,16 +22,10 @@ interface MintCardWrapperProps {
export const MintCardWrapper: React.FC<MintCardWrapperProps> = ({ mintCard, ...props }) => {
const [extendedBankInfos] = useMrgnlendStore((state) => [state.extendedBankInfos]);

const [requestedAction, setRequestedAction] = React.useState<ActionType>(ActionType.MintLST);

const transformedActionGate = React.useMemo(() => getBlockedActions(), []);

const requestedBank = React.useMemo(
() =>
extendedBankInfos.find((bank) => bank?.info?.state?.mint.equals && bank?.info?.state?.mint.equals(LST_MINT)) ??
null,
[extendedBankInfos]
);
const { connected } = useWallet();

return (
<Card variant="default" className="relative">
<CardHeader className="pt-8">
Expand Down Expand Up @@ -71,33 +68,41 @@ export const MintCardWrapper: React.FC<MintCardWrapperProps> = ({ mintCard, ...p
)}

{mintCard.title === "LST" ? (
<ActionBoxDialog
requestedAction={requestedAction}
requestedBank={requestedAction === ActionType.UnstakeLST ? requestedBank : null}
>
<div className="flex items-center gap-2">
<Button
variant="secondary"
size="lg"
className="mt-4"
onClick={() => {
setRequestedAction(ActionType.MintLST);
}}
>
Stake {mintCard.title}
</Button>
<Button
variant="outline-dark"
size="lg"
className="mt-4 hover:text-primary"
onClick={() => {
setRequestedAction(ActionType.UnstakeLST);
}}
>
Unstake {mintCard.title}
</Button>
</div>
</ActionBoxDialog>
<div className="flex items-center gap-2">
<ActionBox.Stake
isDialog={true}
useProvider={true}
stakeProps={{
connected: connected,
requestedActionType: ActionType.MintLST,
}}
dialogProps={{
trigger: (
<Button variant="secondary" size="lg" className="mt-4">
Mint {mintCard.title}
</Button>
),
title: "Mint LST",
}}
/>
<ActionBox.Stake
isDialog={true}
useProvider={true}
stakeProps={{
connected: connected,
requestedActionType: ActionType.UnstakeLST,
requestedBank: extendedBankInfos.find((bank) => bank?.info?.state?.mint.equals(LST_MINT)),
}}
dialogProps={{
trigger: (
<Button variant="outline-dark" size="lg" className="mt-4 hover:text-primary">
Unstake {mintCard.title}
</Button>
),
title: "Unstake LST",
}}
/>
</div>
) : transformedActionGate?.find((value) => value === ActionType.MintYBX) ? (
<div className="flex items-center gap-2">
<Button
Expand All @@ -114,11 +119,7 @@ export const MintCardWrapper: React.FC<MintCardWrapperProps> = ({ mintCard, ...p
</Button>
</div>
) : (
<ActionBoxDialog
requestedAction={ActionType.MintYBX}
requestedBank={null}
//requestedToken={new PublicKey("2s37akK2eyBbp8DZgCm7RtsaEz8eJP3Nxd4urLHQv7yB")}
>
<ActionBoxDialog requestedAction={ActionType.MintYBX} requestedBank={null}>
<div className="flex items-center gap-2">
<Button variant="secondary" size="lg" className="mt-4">
Stake
Expand Down
205 changes: 81 additions & 124 deletions apps/marginfi-v2-ui/src/pages/stake.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React from "react";

import { JupiterProvider } from "@jup-ag/react-hook";

import { groupedNumberFormatterDyn, clampedNumeralFormatter, usdFormatter } from "@mrgnlabs/mrgn-common";

import { useConnection } from "~/hooks/use-connection";
import { useWallet } from "~/components/wallet-v2/hooks/use-wallet.hook";
import { useLstStore, useMrgnlendStore, useUiStore } from "~/store";
import { useMrgnlendStore, useUiStore } from "~/store";
import { LST_MINT } from "~/store/lstStore";

import { ActionComplete } from "~/components/common/ActionComplete";
Expand All @@ -22,6 +20,7 @@ import {
} from "~/components/common/Mint";
import { IntegrationsData, MintCardProps, MintOverview, MintPageState, fetchMintOverview } from "~/utils";
import { PageHeading } from "~/components/common/PageHeading";
import { StakeBoxProvider } from "@mrgnlabs/mrgn-ui";

export default function MintPage() {
const { connection } = useConnection();
Expand All @@ -37,12 +36,6 @@ export default function MintPage() {

const [previousTxn] = useUiStore((state) => [state.previousTxn]);

const [fetchLstState, initialized, setIsRefreshingStore] = useLstStore((state) => [
state.fetchLstState,
state.initialized,
state.setIsRefreshingStore,
]);

const [extendedBankInfos] = useMrgnlendStore((state) => [state.extendedBankInfos]);

const lstBank = React.useMemo(
Expand All @@ -63,37 +56,6 @@ export default function MintPage() {
}
};

React.useEffect(() => {
const fetchData = () => {
setIsRefreshingStore(true);
fetchLstState({ connection, wallet }).catch(console.error);
};

if (debounceId.current) {
clearTimeout(debounceId.current);
}

debounceId.current = setTimeout(() => {
fetchData();

const id = setInterval(() => {
setIsRefreshingStore(true);
fetchLstState().catch(console.error);
}, 30_000);

return () => {
clearInterval(id);
clearTimeout(debounceId.current!);
};
}, 1000);

return () => {
if (debounceId.current) {
clearTimeout(debounceId.current);
}
};
}, [wallet]); // eslint-disable-line react-hooks/exhaustive-deps

const cards = React.useMemo(
() => [
{
Expand Down Expand Up @@ -146,90 +108,85 @@ export default function MintPage() {
}, []);

return (
<>
<JupiterProvider connection={connection} wrapUnwrapSOL={false} platformFeeAndAccounts={undefined}>
<div className="w-full max-w-8xl mx-auto px-4 md:px-8 space-y-20 pb-28">
{!initialized && <Loader label="Loading YBX / LST..." className="mt-8" />}
{initialized && (
<>
<div className="w-full max-w-4xl mx-auto px-4 md:px-0">
<PageHeading
heading={
<>
<span className="leading-normal">Inflation protected</span>
<div className="text-3xl leading-normal flex items-center gap-2 pb-2 justify-center">
<IconSol size={32} />
<p>SOL</p>
<p className="mx-2">and</p>
<IconUsd size={32} />
<p>USD</p>
</div>
</>
}
body={
<p>
The two most important assets on Solana are SOL and USD.
<br className="hidden lg:block" /> Capture inflation automatically with LST and YBX.
</p>
}
/>

<div className="grid grid-cols-1 sm:grid-cols-2 gap-8 md:gap-11 mt-8">
{cards.map((item, idx) => (
<MintCardWrapper mintCard={item} key={idx} />
))}
</div>
</div>

<div className="w-full py-4 px-4 md:px-10 xl:px-16 text-center">
<h2 className="text-3xl font-medium mb-3">Integrations</h2>
<p className="text-muted-foreground">
Ready to integrate YBX?{" "}
<button
className="border-b border-primary text-primary transition-colors hover:text-chartreuse hover:border-chartreuse"
onClick={() => setYbxPartnerDialogOpen(true)}
>
Become a launch partner.
</button>
<StakeBoxProvider>
<div className="w-full max-w-8xl mx-auto px-4 md:px-8 space-y-20 pb-28">
<>
<div className="w-full max-w-4xl mx-auto px-4 md:px-0">
<PageHeading
heading={
<>
<span className="leading-normal">Inflation protected</span>
<div className="text-3xl leading-normal flex items-center gap-2 pb-2 justify-center">
<IconSol size={32} />
<p>SOL</p>
<p className="mx-2">and</p>
<IconUsd size={32} />
<p>USD</p>
</div>
</>
}
body={
<p>
The two most important assets on Solana are SOL and USD.
<br className="hidden lg:block" /> Capture inflation automatically with LST and YBX.
</p>
<div className="flex items-center justify-center flex-wrap gap-8 mt-10 w-full">
{lstBank?.length > 0 ? (
<>
<BankIntegrationCard bank={lstBank[0]} isInLendingMode={true} />
</>
) : (
<IntegrationCardSkeleton />
)}
{integrations?.length > 0
? integrations.map((item, i) => <IntegrationCard integrationsData={item} key={i} />)
: [...new Array(5)].map((_, index) => <IntegrationCardSkeleton key={index} />)}
</div>
</div>
</>
)}
</div>
<YbxDialogNotifications
onClose={() => setYbxNotificationsDialogOpen(false)}
mintPageState={mintPageState}
onHandleChangeMintPage={(state) => setMintPageState(state)}
open={ybxNotificationsDialogOpen}
onOpenChange={(open) => {
setMintPageState(MintPageState.DEFAULT);
setYbxNotificationsDialogOpen(open);
}}
/>
<YbxDialogPartner
onClose={() => setYbxPartnerDialogOpen(false)}
mintPageState={mintPageState}
onHandleChangeMintPage={(state) => setMintPageState(state)}
open={ybxPartnerDialogOpen}
onOpenChange={(open) => {
setMintPageState(MintPageState.DEFAULT);
setYbxPartnerDialogOpen(open);
}}
/>
</JupiterProvider>
{initialized && previousTxn && <ActionComplete />}
</>
}
/>

<div className="grid grid-cols-1 sm:grid-cols-2 gap-8 md:gap-11 mt-8">
{cards.map((item, idx) => (
<MintCardWrapper mintCard={item} key={idx} />
))}
</div>
</div>

<div className="w-full py-4 px-4 md:px-10 xl:px-16 text-center">
<h2 className="text-3xl font-medium mb-3">Integrations</h2>
<p className="text-muted-foreground">
Ready to integrate YBX?{" "}
<button
className="border-b border-primary text-primary transition-colors hover:text-chartreuse hover:border-chartreuse"
onClick={() => setYbxPartnerDialogOpen(true)}
>
Become a launch partner.
</button>
</p>
<div className="flex items-center justify-center flex-wrap gap-8 mt-10 w-full">
{lstBank?.length > 0 ? (
<>
<BankIntegrationCard bank={lstBank[0]} isInLendingMode={true} />
</>
) : (
<IntegrationCardSkeleton />
)}
{integrations?.length > 0
? integrations.map((item, i) => <IntegrationCard integrationsData={item} key={i} />)
: [...new Array(5)].map((_, index) => <IntegrationCardSkeleton key={index} />)}
</div>
</div>
</>
</div>
<YbxDialogNotifications
onClose={() => setYbxNotificationsDialogOpen(false)}
mintPageState={mintPageState}
onHandleChangeMintPage={(state) => setMintPageState(state)}
open={ybxNotificationsDialogOpen}
onOpenChange={(open) => {
setMintPageState(MintPageState.DEFAULT);
setYbxNotificationsDialogOpen(open);
}}
/>
<YbxDialogPartner
onClose={() => setYbxPartnerDialogOpen(false)}
mintPageState={mintPageState}
onHandleChangeMintPage={(state) => setMintPageState(state)}
open={ybxPartnerDialogOpen}
onOpenChange={(open) => {
setMintPageState(MintPageState.DEFAULT);
setYbxPartnerDialogOpen(open);
}}
/>
{previousTxn && <ActionComplete />}
</StakeBoxProvider>
);
}
Loading
Loading