Skip to content

Commit

Permalink
fix apy bugs, use strategies api for fast loading
Browse files Browse the repository at this point in the history
  • Loading branch information
akiraonstarknet committed Oct 2, 2024
1 parent ee8b0e9 commit 14db161
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 97 deletions.
7 changes: 7 additions & 0 deletions src/app/api/stats/[address]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ export async function GET(_req: Request, context: any) {
return {
id: strategy.id,
usdValue: balanceInfo.usdValue,
tokenInfo: {
name: balanceInfo.tokenInfo.name,
symbol: balanceInfo.tokenInfo.name,
logo: balanceInfo.tokenInfo.logo,
decimals: balanceInfo.tokenInfo.decimals,
displayDecimals: balanceInfo.tokenInfo.displayDecimals,
},
amount: balanceInfo.amount.toEtherStr(),
};
});
Expand Down
37 changes: 26 additions & 11 deletions src/app/api/strategies/route.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import { NextResponse } from 'next/server';
import { atom } from 'jotai';
import ZkLendAtoms from '@/store/zklend.store';
import { PoolInfo } from '@/store/pools';
import NostraLendingAtoms from '@/store/nostralending.store';
import ZkLendAtoms, { zkLend } from '@/store/zklend.store';
import { PoolInfo, PoolType } from '@/store/pools';
import NostraLendingAtoms, { nostraLending } from '@/store/nostralending.store';
import { RpcProvider } from 'starknet';
import { getLiveStatusNumber, getStrategies } from '@/store/strategies.atoms';
import { MY_STORE } from '@/store';
import MyNumber from '@/utils/MyNumber';
import { IStrategy, NFTInfo, TokenInfo } from '@/strategies/IStrategy';
import { STRKFarmStrategyAPIResult } from '@/store/strkfarm.atoms';

export const revalidate = 3600; // 1 hr

const allPoolsAtom = atom<PoolInfo[]>((get) => {
const pools: PoolInfo[] = [];
const poolAtoms = [ZkLendAtoms, NostraLendingAtoms];
return poolAtoms.reduce((_pools, p) => _pools.concat(get(p.pools)), pools);
return [];
});

async function getPools(store: any, retry = 0) {
const allPools = store.get(allPoolsAtom);
if (!allPools.length && retry < 10) {
const allPools: PoolInfo[] | undefined = store.get(allPoolsAtom);

const minProtocolsRequired = [zkLend.name, nostraLending.name];
const hasRequiredPools = minProtocolsRequired.every((p) => {
if (!allPools) return false;
return allPools.some(
(pool) => pool.protocol.name === p && pool.type == PoolType.Lending,
);
});
const MAX_RETRIES = 120;
if (retry >= MAX_RETRIES) {
throw new Error('Failed to fetch pools');
} else if (!allPools || !hasRequiredPools) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return getPools(store, retry + 1);
}
if (retry >= 10) {
throw new Error('Failed to fetch pools');
}
return allPools;
}

const provider = new RpcProvider({
nodeUrl: process.env.RPC_URL || 'https://starknet-mainnet.public.blastapi.io',
});

async function getStrategyInfo(strategy: IStrategy) {
async function getStrategyInfo(
strategy: IStrategy,
): Promise<STRKFarmStrategyAPIResult> {
const tvl = await strategy.getTVL();

return {
Expand Down Expand Up @@ -67,8 +77,13 @@ async function getStrategyInfo(strategy: IStrategy) {
export async function GET(req: Request) {
const allPools = await getPools(MY_STORE);
const strategies = getStrategies();

strategies.forEach((strategy) => {
strategy.solve(allPools, '1000');
try {
strategy.solve(allPools, '1000');
} catch (err) {
console.error('Error solving strategy', strategy.name, err);
}
});

const stratsDataProms: any[] = [];
Expand Down
39 changes: 15 additions & 24 deletions src/components/Strategies.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import CONSTANTS from '@/constants';
import { strategiesAtom } from '@/store/strategies.atoms';
import {
Box,
Container,
Link,
Skeleton,
Expand All @@ -15,16 +13,20 @@ import {
} from '@chakra-ui/react';
import { useAtomValue } from 'jotai';
import React, { useMemo } from 'react';
import { userStatsAtom } from '@/store/utils.atoms';
import { allPoolsAtomUnSorted, filteredPools } from '@/store/protocols';
import { addressAtom } from '@/store/claims.atoms';
import { filteredPools } from '@/store/protocols';
import { usePagination } from '@ajna/pagination';
import { YieldStrategyCard } from './YieldCard';
import {
STRKFarmBaseAPYsAtom,
STRKFarmStrategyAPIResult,
} from '@/store/strkfarm.atoms';
export default function Strategies() {
const allPools = useAtomValue(allPoolsAtomUnSorted);
const strategies = useAtomValue(strategiesAtom);
const { data: userData } = useAtomValue(userStatsAtom);
const address = useAtomValue(addressAtom);
const strkFarmPoolsRes = useAtomValue(STRKFarmBaseAPYsAtom);
const strkFarmPools = useMemo(() => {
if (!strkFarmPoolsRes || !strkFarmPoolsRes.data)
return [] as STRKFarmStrategyAPIResult[];
return strkFarmPoolsRes.data.strategies.sort((a, b) => b.apy - a.apy);
}, [strkFarmPoolsRes]);

const _filteredPools = useAtomValue(filteredPools);
const ITEMS_PER_PAGE = 15;
Expand Down Expand Up @@ -57,29 +59,18 @@ export default function Strategies() {
</Tr>
</Thead>
<Tbody>
{allPools.length > 0 && strategies.length > 0 && (
{strkFarmPools.length > 0 && (
<>
{strategies.map((strat, index) => {
{strkFarmPools.map((pool, index) => {
return (
<YieldStrategyCard
key={strat.id}
strat={strat}
index={index}
/>
<YieldStrategyCard key={pool.id} strat={pool} index={index} />
);
})}
</>
)}
</Tbody>
</Table>
{allPools.length > 0 && strategies.length === 0 && (
<Box padding="10px 0" width={'100%'} float={'left'}>
<Text color="light_grey" textAlign={'center'}>
No strategies. Check back soon.
</Text>
</Box>
)}
{allPools.length === 0 && (
{strkFarmPools.length === 0 && (
<Stack>
<Skeleton height="70px" />
<Skeleton height="70px" />
Expand Down
11 changes: 8 additions & 3 deletions src/components/TncModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import axios from 'axios';
import { atomWithQuery } from 'jotai-tanstack-query';
import React, { useEffect, useMemo, useState } from 'react';
import { UserTncInfo } from '@/app/api/interfaces';
import { useAtomValue, useSetAtom } from 'jotai';
import { useAtom, useAtomValue } from 'jotai';
import { referralCodeAtom } from '@/store/referral.store';
import { useSearchParams } from 'next/navigation';
import { generateReferralCode } from '@/utils';
Expand All @@ -44,10 +44,13 @@ export const UserTnCAtom = atomWithQuery((get) => {

const TncModal: React.FC<TncModalProps> = (props) => {
const { address, account } = useAccount();
const setReferralCode = useSetAtom(referralCodeAtom);
const [refCode, setReferralCode] = useAtom(referralCodeAtom);
const searchParams = useSearchParams();
const userTncInfoRes = useAtomValue(UserTnCAtom);
const userTncInfo = useMemo(() => userTncInfoRes.data, [userTncInfoRes]);
const userTncInfo = useMemo(
() => userTncInfoRes.data,
[userTncInfoRes, refCode],
);
const { isOpen, onOpen, onClose } = useDisclosure();
const [isSigningPending, setIsSigningPending] = useState(false);
const { disconnectAsync } = useDisconnect();
Expand All @@ -64,6 +67,8 @@ const TncModal: React.FC<TncModalProps> = (props) => {
!userTncInfo.user.isTncSigned
) {
onOpen();
} else {
onClose();
}
return;
}
Expand Down
84 changes: 63 additions & 21 deletions src/components/YieldCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
VStack,
} from '@chakra-ui/react';
import shield from '@/assets/shield.svg';
import { IStrategyProps, StrategyLiveStatus } from '@/strategies/IStrategy';
import { StrategyLiveStatus } from '@/strategies/IStrategy';
import { useAtomValue } from 'jotai';
import { getDisplayCurrencyAmount } from '@/utils';
import { addressAtom } from '@/store/claims.atoms';
Expand All @@ -32,6 +32,7 @@ import { getPoolInfoFromStrategy } from '@/store/protocols';
import { TriangleDownIcon, TriangleUpIcon } from '@chakra-ui/icons';
import { useState } from 'react';
import mixpanel from 'mixpanel-browser';
import { STRKFarmStrategyAPIResult } from '@/store/strkfarm.atoms';

interface YieldCardProps {
pool: PoolInfo;
Expand Down Expand Up @@ -206,19 +207,38 @@ function isLive(status: StrategyLiveStatus) {
);
}

function getStrategyWiseInfo(
function getStrategyWiseHoldingsInfo(
userData: UserStats | null | undefined,
id: string,
) {
const amount = userData?.strategyWise.find((item) => item.id === id);
return amount?.usdValue ? amount?.usdValue : 0;
if (!amount) {
return {
usdValue: 0,
amount: 0,
tokenInfo: {
symbol: '',
decimals: 0,
displayDecimals: 0,
logo: '',
name: '',
},
};
}
return {
usdValue: amount.usdValue,
amount: Number(amount.amount),
tokenInfo: amount.tokenInfo,
};
}

function StrategyTVL(props: YieldCardProps) {
const { pool } = props;
const address = useAtomValue(addressAtom);
const { data: userData } = useAtomValue(userStatsAtom);

const holdingsInfo = getStrategyWiseHoldingsInfo(userData, pool.pool.id);

const isPoolLive =
pool.additional &&
pool.additional.tags[0] &&
Expand Down Expand Up @@ -247,17 +267,44 @@ function StrategyTVL(props: YieldCardProps) {
borderRadius={'20px'}
color="grey_text"
fontSize={'12px'}
width={'100%'}
mt="5px"
>
<>
<Tooltip label="Your deposits in this STRKFarm strategy">
<Text width={'100%'} textAlign={'right'} fontWeight={600}>
<Icon as={FaWallet} marginRight={'5px'} marginTop={'-2px'} />$
{Math.round(
getStrategyWiseInfo(userData, pool.pool.id),
).toLocaleString()}
</Text>
</Tooltip>
</>
<Tooltip label="Your deposits in this STRKFarm strategy">
<Box width={'100%'} fontWeight={600}>
<Flex>
<Text width={'100%'} justifyContent={'flex-end'}>
${getDisplayCurrencyAmount(holdingsInfo.usdValue, 0)}
</Text>
<Box>
<Icon as={FaWallet} marginLeft={'3px'} mt={'-3px'} />
</Box>
</Flex>
{holdingsInfo.amount != 0 && (
<Flex
justifyContent={'flex-end'}
marginTop={'-5px'}
width={'100%'}
opacity={0.5}
>
{/* <Avatar size={'2xs'} src={holdingsInfo.tokenInfo.logo} mr={'2px'}/> */}
<Text textAlign={'right'} fontSize={'11px'}>
{getDisplayCurrencyAmount(
holdingsInfo.amount,
holdingsInfo.tokenInfo.displayDecimals,
).toLocaleString()}
</Text>
<Image
width={'10px'}
src={holdingsInfo.tokenInfo.logo}
ml={'4px'}
mr={'1px'}
filter={'grayscale(1)'}
/>
</Flex>
)}
</Box>
</Tooltip>
</Box>
)}
</Box>
Expand Down Expand Up @@ -470,16 +517,11 @@ export default function YieldCard(props: YieldCardProps) {
}

export function YieldStrategyCard(props: {
strat: IStrategyProps;
strat: STRKFarmStrategyAPIResult;
index: number;
}) {
const tvlInfo = useAtomValue(props.strat.tvlAtom);
const pool = getPoolInfoFromStrategy(
props.strat,
tvlInfo.data?.usdValue || 0,
);

return <YieldCard pool={pool} index={props.index} showProtocolName={false} />;
const strat = getPoolInfoFromStrategy(props.strat);
return <YieldCard pool={strat} index={props.index} showProtocolName={true} />;
}

export function HeaderSorter(props: {
Expand Down
20 changes: 11 additions & 9 deletions src/store/protocols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ import CarmineAtoms, { carmine } from './carmine.store';
import { atom } from 'jotai';
import { Category, PoolInfo, PoolType } from './pools';
import strkfarmLogo from '@public/logo.png';
import { IStrategyProps } from '@/strategies/IStrategy';
import STRKFarmAtoms, { strkfarm } from './strkfarm.atoms';
import STRKFarmAtoms, {
strkfarm,
STRKFarmStrategyAPIResult,
} from './strkfarm.atoms';
import { getLiveStatusEnum } from './strategies.atoms';

export const PROTOCOLS = [
{
Expand Down Expand Up @@ -151,8 +154,7 @@ export const allPoolsAtomUnSorted = atom((get) => {
});

export function getPoolInfoFromStrategy(
strat: IStrategyProps,
tvlInfo: number,
strat: STRKFarmStrategyAPIResult,
): PoolInfo {
let category = Category.Others;
if (strat.name.includes('STRK')) {
Expand All @@ -164,18 +166,18 @@ export function getPoolInfoFromStrategy(
pool: {
id: strat.id,
name: strat.name,
logos: [strat.holdingTokens[0].logo],
logos: [strat.logo],
},
protocol: {
name: 'STRKFarm',
link: `/strategy/${strat.id}`,
logo: strkfarmLogo.src,
},
tvl: tvlInfo,
apr: strat.netYield,
tvl: strat.tvlUsd,
apr: strat.apy,
aprSplits: [
{
apr: strat.netYield,
apr: strat.apy,
title: 'Net Yield',
description: 'Includes fees & Defi spring rewards',
},
Expand All @@ -191,7 +193,7 @@ export function getPoolInfoFromStrategy(
},
additional: {
riskFactor: strat.riskFactor,
tags: [strat.liveStatus],
tags: [getLiveStatusEnum(strat.status.number)],
isAudited: true,
leverage: strat.leverage,
},
Expand Down
Loading

0 comments on commit 14db161

Please sign in to comment.