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-trading): Arena refactor with optimized fetching & better quote token support #995

Open
wants to merge 56 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
d53b60c
feat: redesigning the tradestore & arena client object (wip)
k0beLeenders Nov 29, 2024
cb8feca
feat: redesigning the tradestore (wip)
k0beLeenders Dec 2, 2024
5b75b6e
feat: redesigning the tradestore (wip)
k0beLeenders Dec 2, 2024
9cdf9ec
feat: redesigned tradestor
k0beLeenders Dec 3, 2024
d6dae1b
feat: linked up home page with new tradestore
k0beLeenders Dec 3, 2024
8e09435
fix: bug fixing and code cleanup
k0beLeenders Dec 3, 2024
20a9a94
feat: improvements & cleanup
k0beLeenders Dec 4, 2024
ba8955e
fix: added setter
k0beLeenders Dec 4, 2024
c443bfa
feat: store integration yield page & mrgnclient helper functions (wip)
k0beLeenders Dec 5, 2024
2561a85
feat: yield page finished & portfolio page wip
k0beLeenders Dec 6, 2024
9eb0f87
feat: refactored the arena with new tradestore
k0beLeenders Dec 9, 2024
2a00e57
feat: updated admin page with new tradestore
k0beLeenders Dec 9, 2024
4360639
feat: merged final pieces to tradestoreV2 & cleanup original tradestore
k0beLeenders Dec 9, 2024
c8ff1a6
chore: removed arena client
k0beLeenders Dec 9, 2024
e95bb7b
fix: small bug of state not being ready & handle empty portfolio
k0beLeenders Dec 9, 2024
9484dd6
fix: small portfolio page improvements
k0beLeenders Dec 9, 2024
f272a65
feat: SSR rendering for arena data
k0beLeenders Dec 10, 2024
192c49b
fix: improved state fetching
k0beLeenders Dec 10, 2024
18874ac
fix: trade detail page
k0beLeenders Dec 11, 2024
122670d
fix: fetchExtendedArenaGroups called at the wrong time
k0beLeenders Dec 11, 2024
0776754
feat: arena powered by marginfi api
k0beLeenders Dec 11, 2024
db71634
chore: fix merge conflicts
k0beLeenders Dec 12, 2024
71d8fe4
fix: icons & trade page 404 redirect
k0beLeenders Dec 12, 2024
88d8c93
fix: SSR host missing
k0beLeenders Dec 12, 2024
0f21521
feat: updated permissionless pools flow
k0beLeenders Dec 12, 2024
3b467c6
feat: added get positions endpoint
k0beLeenders Dec 13, 2024
9bebec7
feat: store integration yield page & mrgnclient helper functions (wip)
k0beLeenders Dec 5, 2024
1cca08f
feat: initial work
borcherd Dec 11, 2024
c5eb15d
feat: refactor stats
borcherd Dec 11, 2024
f8efa69
feat: ui improvements
borcherd Dec 11, 2024
b20d20c
feat: tx simulation
borcherd Dec 11, 2024
0ab395d
feat: various ui fixes & simulation finetuning
borcherd Dec 12, 2024
8c62a3f
feat: tx execution
borcherd Dec 12, 2024
9e1835b
chore: remove logs
borcherd Dec 12, 2024
cddee18
feat: qa changes
borcherd Dec 12, 2024
4e56051
chores: QA fixes & todo implementations
borcherd Dec 13, 2024
db024ec
feat: TODO's & QA fixes
borcherd Dec 13, 2024
ee0da2f
chore: styling changes
borcherd Dec 13, 2024
6749a6c
chore: remove logs
borcherd Dec 13, 2024
aea0473
feat: taillored function to looping & updated formatted
borcherd Dec 13, 2024
2e45be1
chore: remove log
borcherd Dec 13, 2024
e943068
chore: use provided tradeside
borcherd Dec 13, 2024
890f671
feat: updated onComplete and added short-long restriction check
borcherd Dec 13, 2024
d7ed08b
feat: tx fetching & simulation refactor & qa changes
borcherd Dec 13, 2024
4318c16
feat: update stats
borcherd Dec 13, 2024
a90ca74
chore: add url to oracle img
borcherd Dec 13, 2024
5eaed23
feat: better handeling for new accounts & seperated account tx
k0beLeenders Dec 13, 2024
4ccbf66
chore: styling changes
borcherd Dec 13, 2024
89679e0
feat: tx account creation work **WIP**
borcherd Dec 13, 2024
fbc32c4
fix: account tx not being set
k0beLeenders Dec 13, 2024
2b44094
fix: small improvements & refactor
k0beLeenders Dec 14, 2024
600510f
fix: added marginfi account creation
k0beLeenders Dec 14, 2024
8224aee
fix: ata creation missing due to missing metadata
k0beLeenders Dec 14, 2024
b77ba8a
Merge pull request #1003 from mrgnlabs/feat/tradingbox-v2
k0beLeenders Dec 16, 2024
1f938be
fix: fetch priority fee & bundle tip
k0beLeenders Dec 16, 2024
cff3174
feat: error messages, toast fixes & more UI improvements
borcherd Dec 16, 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
34 changes: 14 additions & 20 deletions apps/marginfi-v2-trading/src/components/common/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { cn } from "@mrgnlabs/mrgn-utils";
import { USDC_MINT } from "@mrgnlabs/mrgn-common";
import { Settings } from "@mrgnlabs/mrgn-ui";

import { useTradeStore, useUiStore } from "~/store";
import { useTradeStoreV2, useUiStore } from "~/store";
import { useWallet } from "~/components/wallet-v2/hooks/use-wallet.hook";
import { useIsMobile } from "~/hooks/use-is-mobile";
import { useConnection } from "~/hooks/use-connection";
Expand All @@ -24,6 +24,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "~/comp

import { CreatePoolScriptDialog } from "../Pool/CreatePoolScript";
import { CreatePoolSoon } from "../Pool/CreatePoolSoon";
import { CreatePoolDialog } from "../Pool/CreatePoolDialog";

const navItems = [
{ label: "Discover", href: "/" },
Expand All @@ -33,16 +34,15 @@ const navItems = [

export const Header = () => {
const { connection } = useConnection();
const [initialized, userDataFetched, groupMap, nativeSolBalance, fetchTradeState, referralCode] = useTradeStore(
(state) => [
const [initialized, userDataFetched, nativeSolBalance, fetchTradeState, referralCode, banksByBankPk] =
useTradeStoreV2((state) => [
state.initialized,
state.userDataFetched,
state.groupMap,
state.nativeSolBalance,
state.fetchTradeState,
state.referralCode,
]
);
state.banksByBankPk,
]);
const { priorityType, broadcastType, priorityFees, maxCap, maxCapType, setTransactionSettings } = useUiStore(
(state) => ({
priorityType: state.priorityType,
Expand All @@ -61,19 +61,13 @@ export const Header = () => {
const [isReferralCopied, setIsReferralCopied] = React.useState(false);

const extendedBankInfos = React.useMemo(() => {
const groups = [...groupMap.values()];
const tokens = groups.map((group) => group.pool.token);
const usdc = groups.find((group) => group.pool.quoteTokens[0].info.rawBank.mint.equals(USDC_MINT));

if (!usdc) return tokens;

return [usdc.pool.quoteTokens[0], ...tokens];
}, [groupMap]);
return Object.values(banksByBankPk);
}, [banksByBankPk]);

const ownPools = React.useMemo(() => {
const goups = [...groupMap.values()];
return goups.filter((group) => group?.client.group.admin?.toBase58() === wallet?.publicKey?.toBase58());
}, [groupMap, wallet]);
// const ownPools = React.useMemo(() => {
// const goups = [...groupMap.values()];
// return goups.filter((group) => group?.client.group.admin?.toBase58() === wallet?.publicKey?.toBase58());
// }, [groupMap, wallet]);

React.useEffect(() => {
if (!initialized) return;
Expand Down Expand Up @@ -118,13 +112,13 @@ export const Header = () => {
</ul>
</nav>
<div className={cn("flex items-center gap-2")}>
{ownPools.length > 0 && (
{/* {ownPools.length > 0 && (
<Link href="/admin">
<Button variant="outline" size={isMobile ? "sm" : "default"}>
<IconPlus size={isMobile ? 14 : 18} /> Manage pools
</Button>
</Link>
)}
)} */}
{
// eslint-disable-next-line turbo/no-undeclared-env-vars
process.env.NEXT_PUBLIC_ENABLE_BANK_SCRIPT && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import { IconPlus } from "@tabler/icons-react";
import { PublicKey } from "@solana/web3.js";
import { cn } from "@mrgnlabs/mrgn-utils";

import { useTradeStore } from "~/store";
import { useIsMobile } from "~/hooks/use-is-mobile";

import {
CreatePoolMint,
CreatePoolForm,
CreatePoolSuccess,
CreatePoolState,
CreatePoolToken,
} from "~/components/common/Pool/CreatePoolDialog/";
import { Dialog, DialogContent, DialogTrigger } from "~/components/ui/dialog";
import { Button } from "~/components/ui/button";
import type { TokenData } from "~/types";

import type { PoolData } from "./types";
import type { PoolData, PoolMintData } from "./types";
import { CreatePoolLoading } from "./components/CreatePoolLoading";
import { CreatePoolQuote } from "./components/CreatePoolQuote";

type CreatePoolDialogProps = {
trigger?: React.ReactNode;
Expand All @@ -30,62 +30,77 @@ type CreatePoolDialogProps = {
export type SUPPORTED_QUOTE_BANKS = "USDC" | "LST";

export const CreatePoolDialog = ({ trigger }: CreatePoolDialogProps) => {
const [resetSearchResults, searchBanks] = useTradeStore((state) => [state.resetSearchResults, state.searchBanks]);
// const [resetSearchResults, searchBanks] = useTradeStore((state) => [state.resetSearchResults, state.searchBanks]);
const [isOpen, setIsOpen] = React.useState(false);
const [createPoolState, setCreatePoolState] = React.useState<CreatePoolState>(CreatePoolState.MINT);
const [createPoolState, setCreatePoolState] = React.useState<CreatePoolState>(CreatePoolState.TOKEN);
const [isSearchingToken, setIsSearchingToken] = React.useState(false);
const [isTokenFetchingError, setIsTokenFetchingError] = React.useState(false);
const [searchQuery, setSearchQuery] = React.useState("");
const [mintAddress, setMintAddress] = React.useState("");
const [poolData, setPoolData] = React.useState<PoolData | null>(null);
const [quoteBank, setQuoteBank] = React.useState<SUPPORTED_QUOTE_BANKS>("USDC");
const [isSubmitting, setIsSubmitting] = React.useState(false);

const { width, height } = useWindowSize();
const isMobile = useIsMobile();

const fetchTokenInfo = React.useCallback(async () => {
setIsSearchingToken(true);

try {
const mint = new PublicKey(mintAddress);
const fetchTokenReq = await fetch(`/api/birdeye/token?address=${mint.toBase58()}`);

if (!fetchTokenReq.ok) {
throw new Error("Failed to fetch token info");
}

const tokenInfo = (await fetchTokenReq.json()) as TokenData;
if (!tokenInfo) {
throw new Error("Could not find token info");
const fetchTokenInfo = React.useCallback(
async (mintAddress: string) => {
setIsSearchingToken(true);

try {
const mint = new PublicKey(mintAddress);
const fetchTokenReq = await fetch(`/api/birdeye/token?address=${mint.toBase58()}`);

if (!fetchTokenReq.ok) {
throw new Error("Failed to fetch token info");
}

const tokenInfo = (await fetchTokenReq.json()) as TokenData;
if (!tokenInfo) {
throw new Error("Could not find token info");
}

const mintData: PoolMintData = {
mint: new PublicKey(tokenInfo.address),
name: tokenInfo.name,
symbol: tokenInfo.symbol,
icon: tokenInfo.imageUrl,
decimals: tokenInfo.decimals,
};

setIsSearchingToken(false);
if (createPoolState === CreatePoolState.QUOTE) {
setPoolData((prev) => {
if (!prev) return null;
return {
...prev,
quoteToken: mintData,
};
});
setCreatePoolState(CreatePoolState.FORM);
} else {
setPoolData({
token: mintData,
});
setCreatePoolState(CreatePoolState.QUOTE);
}
} catch (e) {
console.error(e);
setPoolData(null);
setIsTokenFetchingError(true);
setIsSearchingToken(false);
}
},
[createPoolState]
);

setPoolData({
mint: new PublicKey(tokenInfo.address),
name: tokenInfo.name,
symbol: tokenInfo.symbol,
icon: tokenInfo.imageUrl,
decimals: tokenInfo.decimals,
quoteBank: "USDC",
});

setIsSearchingToken(false);
setCreatePoolState(CreatePoolState.FORM);
} catch (e) {
console.error(e);
setPoolData(null);
setIsTokenFetchingError(true);
setIsSearchingToken(false);
}
}, [mintAddress]);

React.useEffect(() => {
if (!searchQuery.length) {
resetSearchResults();
return;
}
searchBanks(searchQuery);
}, [searchBanks, resetSearchResults, searchQuery]);
// React.useEffect(() => {
// if (!searchQuery.length) {
// resetSearchResults();
// return;
// }
// searchBanks(searchQuery);
// }, [searchBanks, resetSearchResults, searchQuery]);

const reset = React.useCallback(() => {
setIsSearchingToken(false);
Expand All @@ -97,9 +112,8 @@ export const CreatePoolDialog = ({ trigger }: CreatePoolDialogProps) => {
React.useEffect(() => {
reset();
setSearchQuery("");
setMintAddress("");
setCreatePoolState(CreatePoolState.MINT);
}, [isOpen, reset, setSearchQuery, setMintAddress, setCreatePoolState]);
setCreatePoolState(CreatePoolState.TOKEN);
}, [isOpen, reset, setSearchQuery, setCreatePoolState]);

return (
<>
Expand All @@ -117,7 +131,7 @@ export const CreatePoolDialog = ({ trigger }: CreatePoolDialogProps) => {
<Dialog
open={isOpen}
onOpenChange={(open) => {
if (!open) resetSearchResults();
// if (!open) resetSearchResults();
setIsOpen(open);
}}
>
Expand All @@ -131,11 +145,17 @@ export const CreatePoolDialog = ({ trigger }: CreatePoolDialogProps) => {
)}
</DialogTrigger>
<DialogContent className="w-full space-y-4 sm:max-w-4xl md:max-w-4xl z-[70]">
{createPoolState === CreatePoolState.MINT && (
<CreatePoolMint
mintAddress={mintAddress}
{createPoolState === CreatePoolState.TOKEN && (
<CreatePoolToken
isSearchingToken={isSearchingToken}
fetchTokenInfo={fetchTokenInfo}
setIsOpen={setIsOpen}
/>
)}
{createPoolState === CreatePoolState.QUOTE && (
<CreatePoolQuote
tokenMintAddress={poolData?.token?.mint.toBase58() ?? ""}
isSearchingToken={isSearchingToken}
setMintAddress={setMintAddress}
fetchTokenInfo={fetchTokenInfo}
setIsOpen={setIsOpen}
/>
Expand Down
Loading
Loading