Skip to content

Commit

Permalink
Harvest timer (#147)
Browse files Browse the repository at this point in the history
* feat: harvest time ui

* feat: display API data

* fix: imports

* fix: lint

* fix: remove mock contract

* fix: remove mock contract

* fix: change query

* fix harvest timer: standarise address

* fix harvest timer bugs

* fix harvest timer bugs [2]

* fix harvest timer bugs [3]

---------

Co-authored-by: Iwueseiter <[email protected]>
  • Loading branch information
akiraonstarknet and Iwueseiter authored Sep 27, 2024
1 parent e9f234a commit 43ee68b
Show file tree
Hide file tree
Showing 4 changed files with 344 additions and 30 deletions.
37 changes: 9 additions & 28 deletions src/app/strategy/[strategyId]/_components/Strategy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ import {
ListItem,
OrderedList,
Spinner,
Stat,
StatHelpText,
StatLabel,
StatNumber,
Tab,
TabIndicator,
TabList,
Expand All @@ -32,13 +28,12 @@ import { useAccount } from '@starknet-react/core';
import { atom, useAtomValue, useSetAtom } from 'jotai';
import mixpanel from 'mixpanel-browser';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { isMobile } from 'react-device-detect';

import Deposit from '@/components/Deposit';
import CONSTANTS from '@/constants';
import { DUMMY_BAL_ATOM } from '@/store/balance.atoms';
import { StrategyInfo, strategiesAtom } from '@/store/strategies.atoms';
import { transactionsAtom, TxHistoryAtom } from '@/store/transactions.atom';
import HarvestTime from '@/components/HarvestTime';
import {
capitalize,
getTokenInfoFromAddr,
Expand All @@ -49,6 +44,8 @@ import {
import { StrategyParams } from '../page';
import MyNumber from '@/utils/MyNumber';
import { ExternalLinkIcon } from '@chakra-ui/icons';
import { isMobile } from 'react-device-detect';
import CONSTANTS from '@/constants';

const Strategy = ({ params }: StrategyParams) => {
const { address } = useAccount();
Expand Down Expand Up @@ -177,13 +174,15 @@ const Strategy = ({ params }: StrategyParams) => {
{strategy ? strategy.name : 'Strategy Not found'}
</Text>
</Flex>

{strategy && (
<VStack width={'100%'}>
<Grid width={'100%'} templateColumns="repeat(5, 1fr)" gap={2}>
<GridItem display="flex" colSpan={colSpan1}>
<Card width="100%" padding={'15px'} color="white" bg="highlight">
<Box display={{ base: 'block', md: 'flex' }}>
<Box width={{ base: '100%', md: '80%' }} float={'left'}>
<HarvestTime strategy={strategy} balData={balData} />
<Box display={{ base: 'block', md: 'flex' }} marginTop={'10px'}>
<Box width={{ base: '100%', md: '100%' }}>
<Text
fontSize={'20px'}
marginBottom={'0px'}
Expand Down Expand Up @@ -219,26 +218,6 @@ const Strategy = ({ params }: StrategyParams) => {
))}
</Wrap>
</Box>
<Box
width={{ base: '100%', md: '20%' }}
float={'left'}
marginTop={{ base: '10px' }}
>
<Stat>
<StatLabel textAlign={{ base: 'left', md: 'right' }}>
APY
</StatLabel>
<StatNumber
color="cyan"
textAlign={{ base: 'left', md: 'right' }}
>
{(strategy.netYield * 100).toFixed(2)}%
</StatNumber>
<StatHelpText textAlign={{ base: 'left', md: 'right' }}>
{strategy.leverage.toFixed(2)}x boosted
</StatHelpText>
</Stat>
</Box>
</Box>
<Box
padding={'10px'}
Expand Down Expand Up @@ -310,6 +289,7 @@ const Strategy = ({ params }: StrategyParams) => {
</Box>
</Card>
</GridItem>

<GridItem display="flex" colSpan={colSpan2}>
<Card width="100%" padding={'15px'} color="white" bg="highlight">
<Tabs position="relative" variant="unstyled" width={'100%'}>
Expand Down Expand Up @@ -370,6 +350,7 @@ const Strategy = ({ params }: StrategyParams) => {
</Card>
</GridItem>
</Grid>

<Card width={'100%'} color="white" bg="highlight" padding={'15px'}>
<Text fontSize={'20px'} marginBottom={'0px'} fontWeight={'bold'}>
Behind the scenes
Expand Down
224 changes: 224 additions & 0 deletions src/components/HarvestTime.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import React, { useMemo } from 'react';
import {
Box,
Flex,
Stat,
StatLabel,
StatNumber,
Tag,
Text,
Tooltip,
} from '@chakra-ui/react';
import { useAccount } from '@starknet-react/core';
import { StrategyInfo } from '@/store/strategies.atoms';
import { HarvestTimeAtom } from '@/store/harvest.atom';
import { useAtomValue } from 'jotai';
import { formatTimediff, getDisplayCurrencyAmount, timeAgo } from '@/utils';
import { isMobile } from 'react-device-detect';

interface HarvestTimeProps {
strategy: StrategyInfo;
balData: any;
}

const HarvestTime: React.FC<HarvestTimeProps> = ({ strategy, balData }) => {
const { address } = useAccount();
const holdingToken: any = strategy.holdingTokens[0];
const contractAddress = holdingToken.address || holdingToken.token || '';

const harvestTimeAtom = useMemo(
() => HarvestTimeAtom(contractAddress),
[address],
);

const harvestTime = useAtomValue(harvestTimeAtom);

const data = harvestTime.data?.findManyHarvests[0];

const lastHarvest = useMemo(() => {
if (!data || !data.timestamp) return null;
return new Date(Number(data.timestamp) * 1000);
}, [data?.timestamp]);

const harvestTimestamp = useMemo(() => {
const DAYMS = 86400 * 1000;
// Base date is last harvest time + 2 days or now (for no harvest strats)
const baseDate = lastHarvest
? new Date(lastHarvest.getTime() + 2 * DAYMS)
: new Date();

// With base date, get next sunday 12am UTC
// set date to coming sunday in UTC
const nextHarvest = baseDate;
nextHarvest.setUTCDate(
nextHarvest.getUTCDate() + (7 - nextHarvest.getUTCDay()),
);
nextHarvest.setUTCHours(0);
nextHarvest.setUTCMinutes(0);
nextHarvest.setUTCSeconds(0);

// if nextHarvest is within 24hrs of last harvest,
// increase it by 7 days
// This is needed as harvest can happen anytime near deadline
if (
lastHarvest &&
nextHarvest.getTime() - lastHarvest.getTime() < 86400 * 1000
) {
nextHarvest.setUTCDate(nextHarvest.getUTCDate() + 7);
}

return formatTimediff(nextHarvest);
}, [data?.timestamp]);

return (
<Box>
<Flex justifyContent="space-between">
<Flex>
<Stat
marginRight={'5px'}
display={'flex'}
flexDirection={'column'}
justifyContent={'flex-end'}
>
<StatLabel>APY</StatLabel>
<StatNumber color="cyan" lineHeight="24px">
{(strategy.netYield * 100).toFixed(2)}%
</StatNumber>
</Stat>
<Flex flexDirection={'column'} justifyContent={'flex-end'}>
<Tooltip label="This shows how much higher your yield is compared to zKLend">
<Tag
bg="bg"
color={'white'}
fontSize={'12px'}
padding={'2px 5px'}
>
🔥{strategy.leverage.toFixed(2)}x boosted
</Tag>
</Tooltip>
</Flex>
</Flex>

{!isMobile && (
<Tooltip
label={`This is when your investment increases as STRK rewards are automatically claimed and reinvested into the strategy's tokens.`}
>
<Box>
<Text
color="#D4D4D6"
fontSize="14px"
fontWeight="500"
display={'flex'}
>
Next Harvest in:{' '}
{harvestTimestamp.isZero && (
<Text color={'cyan'} fontWeight={'bold'} marginLeft={'5px'}>
Anytime now
</Text>
)}
</Text>
<Box
display="flex"
alignItems="center"
pt="5px"
gap="10px"
justifyContent="space-between"
>
<Box
display="flex"
alignItems="center"
justifyContent="center"
flexDirection="column"
gap="4px"
bgColor="color2_50p"
width="53px"
height="53px"
borderRadius="8px"
>
<Text color="#AEAEAE" fontSize="12px" fontWeight="300">
Days
</Text>
<Text color="white" fontWeight="semi-bold">
{harvestTimestamp.days ?? 0}
</Text>
</Box>

<Box
display="flex"
alignItems="center"
justifyContent="center"
flexDirection="column"
gap="4px"
bgColor="color2_50p"
width="53px"
height="53px"
borderRadius="8px"
>
<Text color="#AEAEAE" fontSize="12px" fontWeight="300">
Hour
</Text>
<Text color="white" fontWeight="semi-bold">
{harvestTimestamp.hours ?? 0}
</Text>
</Box>

<Box
display="flex"
alignItems="center"
justifyContent="center"
flexDirection="column"
gap="4px"
bgColor="color2_50p"
width="53px"
height="53px"
borderRadius="8px"
>
<Text color="#AEAEAE" fontSize="12px" fontWeight="300">
Mins
</Text>
<Text color="white" fontWeight="semi-bold">
{harvestTimestamp.minutes ?? 0}
</Text>
</Box>
</Box>
</Box>
</Tooltip>
)}
</Flex>

<Box
display="flex"
padding="5px"
width={'100%'}
bg="bg"
marginTop={'10px'}
borderRadius={'5px'}
>
<Text
color="white"
fontSize="12px"
fontWeight="normal"
textAlign={isMobile ? 'left' : 'right'}
width={'100%'}
>
Harvested{' '}
<b>
{getDisplayCurrencyAmount(
harvestTime?.data?.totalStrkHarvestedByContract.STRKAmount || 0,
2,
)}{' '}
STRK
</b>{' '}
over <b>{harvestTime?.data?.totalHarvestsByContract} claims.</b>{' '}
{lastHarvest && (
<span>
Last harvested <b>{timeAgo(lastHarvest)}</b>.
</span>
)}
</Text>
</Box>
</Box>
);
};

export default HarvestTime;
Loading

0 comments on commit 43ee68b

Please sign in to comment.