Skip to content

Commit

Permalink
✨ Implement new cbBTC/USDC Merit Action aprs (#2222)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinGbz authored Oct 23, 2024
1 parent 9652020 commit 9404b69
Show file tree
Hide file tree
Showing 18 changed files with 273 additions and 158 deletions.
49 changes: 9 additions & 40 deletions src/components/incentives/IncentivesButton.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ProtocolAction } from '@aave/contract-helpers';
import { valueToBigNumber } from '@aave/math-utils';
import { ReserveIncentiveResponse } from '@aave/math-utils/dist/esm/formatters/incentive/calculate-reserve-incentives';
import { DotsHorizontalIcon } from '@heroicons/react/solid';
import { Box, SvgIcon, Typography } from '@mui/material';
import { useState } from 'react';
import { useMeritIncentives, useUserMeritIncentives } from 'src/hooks/useMeritIncentives';
import { useMeritIncentives } from 'src/hooks/useMeritIncentives';
import { useRootStore } from 'src/store/root';
import { DASHBOARD } from 'src/utils/mixPanelEvents';

Expand Down Expand Up @@ -36,53 +37,21 @@ const BlankIncentives = () => {
);
};

export const UserMeritIncentivesButton = ({ symbol }: { symbol: 'gho' | 'stkgho' }) => {
const [open, setOpen] = useState(false);
const { data: meritIncentives } = useUserMeritIncentives();

if (!meritIncentives) {
return null;
}

const incentives = {
incentiveAPR: (meritIncentives.actionsAPR[symbol] / 100).toString(),
rewardTokenSymbol: 'GHO', // rewards alwasy in gho, for now
rewardTokenAddress: '0x', // not used for merit program
};

return (
<ContentWithTooltip
tooltipContent={
<MeritIncentivesTooltipContent
incentiveAPR={incentives.incentiveAPR}
rewardTokenSymbol={incentives.rewardTokenSymbol}
/>
}
withoutHover
setOpen={setOpen}
open={open}
>
<Content incentives={[incentives]} incentivesNetAPR={+incentives.incentiveAPR} />
</ContentWithTooltip>
);
};

export const MeritIncentivesButton = ({ symbol }: { symbol: 'gho' | 'stkgho' }) => {
export const MeritIncentivesButton = (params: {
symbol: string;
market: string;
protocolAction?: ProtocolAction;
}) => {
const [open, setOpen] = useState(false);
const { data: meritIncentives } = useMeritIncentives(symbol);
const { data: meritIncentives } = useMeritIncentives(params);

if (!meritIncentives) {
return null;
}

return (
<ContentWithTooltip
tooltipContent={
<MeritIncentivesTooltipContent
incentiveAPR={meritIncentives.incentiveAPR}
rewardTokenSymbol={meritIncentives.rewardTokenSymbol}
/>
}
tooltipContent={<MeritIncentivesTooltipContent meritIncentives={meritIncentives} />}
withoutHover
setOpen={setOpen}
open={open}
Expand Down
5 changes: 5 additions & 0 deletions src/components/incentives/IncentivesTooltipContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ const IncentivesSymbolMap: {
symbol: 'awstETH',
aToken: true,
},
aEthUSDC: {
tokenIconSymbol: 'USDC',
symbol: 'aUSDC',
aToken: true,
},
};

interface IncentivesTooltipContentProps {
Expand Down
24 changes: 18 additions & 6 deletions src/components/incentives/MeritIncentivesTooltipContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ import { FormattedNumber } from '../primitives/FormattedNumber';
import { Link } from '../primitives/Link';
import { Row } from '../primitives/Row';
import { TokenIcon } from '../primitives/TokenIcon';
import { getSymbolMap } from './IncentivesTooltipContent';

export const MeritIncentivesTooltipContent = ({
incentiveAPR,
rewardTokenSymbol,
}: Omit<ReserveIncentiveResponse, 'rewardTokenAddress'>) => {
meritIncentives,
}: {
meritIncentives: ReserveIncentiveResponse;
}) => {
const typographyVariant = 'secondary12';

const meritIncentivesFormatted = getSymbolMap(meritIncentives);

return (
<Box
sx={{
Expand Down Expand Up @@ -65,14 +69,22 @@ export const MeritIncentivesTooltipContent = ({
mb: 0,
}}
>
<TokenIcon symbol={rewardTokenSymbol} sx={{ fontSize: '20px', mr: 1 }} />
<Typography variant={typographyVariant}>{rewardTokenSymbol}</Typography>
<TokenIcon
aToken={meritIncentivesFormatted.aToken}
symbol={meritIncentivesFormatted.tokenIconSymbol}
sx={{ fontSize: '20px', mr: 1 }}
/>
<Typography variant={typographyVariant}>{meritIncentivesFormatted.symbol}</Typography>
</Box>
}
width="100%"
>
<Box sx={{ display: 'inline-flex', alignItems: 'center' }}>
<FormattedNumber value={+incentiveAPR} percent variant={typographyVariant} />
<FormattedNumber
value={+meritIncentivesFormatted.incentiveAPR}
percent
variant={typographyVariant}
/>
<Typography variant={typographyVariant} sx={{ ml: 1 }}>
<Trans>APR</Trans>
</Typography>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import { TokenIcon } from 'src/components/primitives/TokenIcon';
import { Warning } from 'src/components/primitives/Warning';
import { useGeneralStakeUiData } from 'src/hooks/stake/useGeneralStakeUiData';
import { useUserStakeUiData } from 'src/hooks/stake/useUserStakeUiData';
import { useUserMeritIncentives } from 'src/hooks/useMeritIncentives';
import { useMeritIncentives } from 'src/hooks/useMeritIncentives';
import { useModalContext } from 'src/hooks/useModal';
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
import { useRootStore } from 'src/store/root';
import { stakeConfig } from 'src/ui-config/stakeConfig';
import { getNetworkConfig } from 'src/utils/marketsAndNetworksConfig';
import { CustomMarket, getNetworkConfig } from 'src/utils/marketsAndNetworksConfig';
import { GENERAL } from 'src/utils/mixPanelEvents';

import { formattedTime, timeText } from '../../../helpers/timeHelper';
Expand Down Expand Up @@ -58,8 +58,11 @@ export const StakeCooldownModalContent = ({ stakeAssetName, icon }: StakeCooldow
const { data: stakeUserResult } = useUserStakeUiData(currentMarketData, stakeAssetName);
const { data: stakeGeneralResult } = useGeneralStakeUiData(currentMarketData, stakeAssetName);

const { data: meritIncentives } = useUserMeritIncentives();
const usersStkGhoIncentives = meritIncentives?.actionsAPR.stkgho || 0;
const { data: meritIncentives } = useMeritIncentives({
symbol: 'GHO',
market: CustomMarket.proto_mainnet_v3,
});
const usersStkGhoIncentives = meritIncentives?.incentiveAPR || 0;

// states
const [cooldownCheck, setCooldownCheck] = useState(false);
Expand Down
84 changes: 62 additions & 22 deletions src/hooks/useMeritIncentives.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,87 @@
import { ProtocolAction } from '@aave/contract-helpers';
import { ReserveIncentiveResponse } from '@aave/math-utils/dist/esm/formatters/incentive/calculate-reserve-incentives';
import { AaveV3Ethereum } from '@bgd-labs/aave-address-book';
import { useQuery } from '@tanstack/react-query';
import { useRootStore } from 'src/store/root';
import { CustomMarket } from 'src/ui-config/marketsConfig';

export enum MeritAction {
ETHEREUM_STKGHO = 'ethereum-stkgho',
SUPPLY_CBBTC_BORROW_USDC = 'ethereum-supply-cbbtc-borrow-usdc',
}

type MeritIncentives = {
totalAPR: number;
actionsAPR: {
stkgho: number;
gho: number;
[key in MeritAction]: number;
};
};

const url = 'https://apps.aavechan.com/api/merit/aprs';

export const useMeritIncentives = (asset: 'gho' | 'stkgho') => {
export type MeritReserveIncentiveData = Omit<ReserveIncentiveResponse, 'incentiveAPR'> & {
action: MeritAction;
protocolAction?: ProtocolAction;
};

const getMeritData = (market: string, symbol: string): MeritReserveIncentiveData | undefined =>
MERIT_DATA_MAP[market]?.[symbol];

const MERIT_DATA_MAP: Record<string, Record<string, MeritReserveIncentiveData>> = {
[CustomMarket.proto_mainnet_v3]: {
GHO: {
action: MeritAction.ETHEREUM_STKGHO,
rewardTokenAddress: AaveV3Ethereum.ASSETS.GHO.UNDERLYING,
rewardTokenSymbol: 'GHO',
},
cbBTC: {
action: MeritAction.SUPPLY_CBBTC_BORROW_USDC,
rewardTokenAddress: AaveV3Ethereum.ASSETS.USDC.A_TOKEN,
rewardTokenSymbol: 'aEthUSDC',
protocolAction: ProtocolAction.supply,
},
USDC: {
action: MeritAction.SUPPLY_CBBTC_BORROW_USDC,
rewardTokenAddress: AaveV3Ethereum.ASSETS.USDC.A_TOKEN,
rewardTokenSymbol: 'aEthUSDC',
protocolAction: ProtocolAction.borrow,
},
},
};

export const useMeritIncentives = ({
symbol,
market,
protocolAction,
}: {
symbol: string;
market: string;
protocolAction?: ProtocolAction;
}) => {
return useQuery({
queryFn: async () => {
const response = await fetch(url);
const data = await response.json();
return data.currentAPR as MeritIncentives;
const meritIncentives = data.currentAPR as MeritIncentives;

return meritIncentives;
},
queryKey: ['meritIncentives'],
staleTime: 1000 * 60 * 5,
select: (data) => {
// rewards are always in GHO, for now
const meritReserveIncentiveData = getMeritData(market, symbol);
if (!meritReserveIncentiveData) {
return null;
}
if (meritReserveIncentiveData.protocolAction !== protocolAction) {
return null;
}

const APR = data.actionsAPR[meritReserveIncentiveData.action];
return {
incentiveAPR: (data.actionsAPR[asset] / 100).toString(),
rewardTokenAddress: AaveV3Ethereum.ASSETS.GHO.UNDERLYING,
rewardTokenSymbol: 'GHO',
incentiveAPR: (APR / 100).toString(),
rewardTokenAddress: meritReserveIncentiveData.rewardTokenAddress,
rewardTokenSymbol: meritReserveIncentiveData.rewardTokenSymbol,
} as ReserveIncentiveResponse;
},
});
};

export const useUserMeritIncentives = () => {
const user = useRootStore((store) => store.account);
return useQuery({
queryFn: async () => {
const response = await fetch(`${url}?user=${user}`);
const data = await response.json();
return data.currentAPR as MeritIncentives;
},
queryKey: ['meritIncentives', user],
staleTime: 1000 * 60 * 5,
});
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ProtocolAction } from '@aave/contract-helpers';
import { Trans } from '@lingui/macro';
import { Button } from '@mui/material';
import { useModalContext } from 'src/hooks/useModal';
import { useProtocolDataContext } from 'src/hooks/useProtocolDataContext';
import { useRootStore } from 'src/store/root';
import { DashboardReserve } from 'src/utils/dashboardSortUtils';
import { DASHBOARD } from 'src/utils/mixPanelEvents';
import { showExternalIncentivesTooltip, Side } from 'src/utils/utils';
import { showExternalIncentivesTooltip } from 'src/utils/utils';

import { CapsHint } from '../../../../components/caps/CapsHint';
import { CapType } from '../../../../components/caps/helper';
Expand Down Expand Up @@ -46,7 +47,7 @@ export const BorrowAssetsListItem = ({
showExternalIncentivesTooltips={showExternalIncentivesTooltip(
symbol,
currentMarket,
Side.BORROW
ProtocolAction.borrow
)}
>
<ListValueColumn
Expand All @@ -66,6 +67,8 @@ export const BorrowAssetsListItem = ({
/>
<ListAPRColumn
value={Number(variableBorrowRate)}
market={currentMarket}
protocolAction={ProtocolAction.borrow}
incentives={vIncentivesData}
symbol={symbol}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { ProtocolAction } from '@aave/contract-helpers';
import { Trans } from '@lingui/macro';
import { Box, Button } from '@mui/material';
import { MeritIncentivesButton } from 'src/components/incentives/IncentivesButton';
import { VariableAPYTooltip } from 'src/components/infoTooltips/VariableAPYTooltip';
import { useProtocolDataContext } from 'src/hooks/useProtocolDataContext';
import { DashboardReserve } from 'src/utils/dashboardSortUtils';
import { showExternalIncentivesTooltip, Side } from 'src/utils/utils';
import { showExternalIncentivesTooltip } from 'src/utils/utils';

import { CapsHint } from '../../../../components/caps/CapsHint';
import { CapType } from '../../../../components/caps/helper';
Expand Down Expand Up @@ -42,7 +44,7 @@ export const BorrowAssetsListMobileItem = ({
showExternalIncentivesTooltips={showExternalIncentivesTooltip(
symbol,
currentMarket,
Side.BORROW
ProtocolAction.borrow
)}
>
<ListValueRow
Expand Down Expand Up @@ -71,12 +73,19 @@ export const BorrowAssetsListMobileItem = ({
captionVariant="description"
mb={2}
>
<IncentivesCard
value={Number(variableBorrowRate)}
incentives={vIncentivesData}
symbol={symbol}
variant="secondary14"
/>
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<IncentivesCard
value={Number(variableBorrowRate)}
incentives={vIncentivesData}
symbol={symbol}
variant="secondary14"
/>
<MeritIncentivesButton
symbol={symbol}
market={currentMarket}
protocolAction={ProtocolAction.borrow}
/>
</Box>
</Row>
{/* <Row
caption={
Expand Down
Loading

3 comments on commit 9404b69

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit was deployed on ipfs

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit was deployed on ipfs

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit was deployed on ipfs

Please sign in to comment.