Skip to content

Commit fa0d774

Browse files
MartinGbzNandyBa
andauthored
Implement a new Merkl incentives tooltip (#2516)
Co-authored-by: Nandy Bâ <[email protected]>
1 parent a51325f commit fa0d774

File tree

12 files changed

+144
-91
lines changed

12 files changed

+144
-91
lines changed

public/icons/other/merkl-black.svg

Lines changed: 1 addition & 0 deletions
Loading

public/icons/other/merkl-white.svg

Lines changed: 1 addition & 0 deletions
Loading

src/components/incentives/IncentivesButton.tsx

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { useState } from 'react';
77
import { useEthenaIncentives } from 'src/hooks/useEthenaIncentives';
88
import { useEtherfiIncentives } from 'src/hooks/useEtherfiIncentives';
99
import { useMeritIncentives } from 'src/hooks/useMeritIncentives';
10+
import { useMerklIgniteIncentives } from 'src/hooks/useMerklIncentives';
1011
import { useSonicIncentives } from 'src/hooks/useSonicIncentives';
11-
import { useZkSyncIgniteIncentives } from 'src/hooks/useZkSyncIgniteIncentives';
1212
import { useRootStore } from 'src/store/root';
1313
import { DASHBOARD } from 'src/utils/events';
1414

@@ -19,8 +19,8 @@ import { EthenaAirdropTooltipContent } from './EthenaIncentivesTooltipContent';
1919
import { EtherFiAirdropTooltipContent } from './EtherfiIncentivesTooltipContent';
2020
import { getSymbolMap, IncentivesTooltipContent } from './IncentivesTooltipContent';
2121
import { MeritIncentivesTooltipContent } from './MeritIncentivesTooltipContent';
22+
import { MerklIncentivesTooltipContent } from './MerklIncentivesTooltipContent';
2223
import { SonicAirdropTooltipContent } from './SonicIncentivesTooltipContent';
23-
import { ZkSyncIgniteIncentivesTooltipContent } from './ZkSyncIgniteIncentivesTooltipContent';
2424

2525
interface IncentivesButtonProps {
2626
symbol: string;
@@ -69,31 +69,26 @@ export const MeritIncentivesButton = (params: {
6969
);
7070
};
7171

72-
export const ZkIgniteIncentivesButton = (params: {
72+
export const MerklIncentivesButton = (params: {
7373
market: string;
7474
rewardedAsset?: string;
7575
protocolAction?: ProtocolAction;
7676
}) => {
7777
const [open, setOpen] = useState(false);
78-
const { data: zkSyncIgniteIncentives } = useZkSyncIgniteIncentives(params);
78+
const { data: merklIncentives } = useMerklIgniteIncentives(params);
7979

80-
if (!zkSyncIgniteIncentives) {
80+
if (!merklIncentives) {
8181
return null;
8282
}
8383

8484
return (
8585
<ContentWithTooltip
86-
tooltipContent={
87-
<ZkSyncIgniteIncentivesTooltipContent zkSyncIgniteIncentives={zkSyncIgniteIncentives} />
88-
}
86+
tooltipContent={<MerklIncentivesTooltipContent merklIncentives={merklIncentives} />}
8987
withoutHover
9088
setOpen={setOpen}
9189
open={open}
9290
>
93-
<Content
94-
incentives={[zkSyncIgniteIncentives]}
95-
incentivesNetAPR={+zkSyncIgniteIncentives.incentiveAPR}
96-
/>
91+
<Content incentives={[merklIncentives]} incentivesNetAPR={+merklIncentives.incentiveAPR} />
9792
</ContentWithTooltip>
9893
);
9994
};

src/components/incentives/IncentivesCard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import {
1010
EtherfiIncentivesButton,
1111
IncentivesButton,
1212
MeritIncentivesButton,
13+
MerklIncentivesButton,
1314
SonicIncentivesButton,
14-
ZkIgniteIncentivesButton,
1515
} from './IncentivesButton';
1616

1717
interface IncentivesCardProps {
@@ -89,7 +89,7 @@ export const IncentivesCard = ({
8989
>
9090
<IncentivesButton incentives={incentives} symbol={symbol} />
9191
<MeritIncentivesButton symbol={symbol} market={market} protocolAction={protocolAction} />
92-
<ZkIgniteIncentivesButton
92+
<MerklIncentivesButton
9393
market={market}
9494
rewardedAsset={address}
9595
protocolAction={protocolAction}

src/components/incentives/IncentivesTooltipContent.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ const IncentivesSymbolMap: {
103103
symbol: 'aEURe',
104104
aToken: true,
105105
},
106+
aEthUSDtb: {
107+
tokenIconSymbol: 'USDtb',
108+
symbol: 'aUSDtb',
109+
aToken: true,
110+
},
106111
aSonstS: {
107112
tokenIconSymbol: 'stS',
108113
symbol: 'astS',

src/components/incentives/ZkSyncIgniteIncentivesTooltipContent.tsx renamed to src/components/incentives/MerklIncentivesTooltipContent.tsx

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import { Trans } from '@lingui/macro';
2-
import { Box, Typography } from '@mui/material';
3-
import { ExtendedReserveIncentiveResponse } from 'src/hooks/useZkSyncIgniteIncentives';
2+
import { Box, Typography, useTheme } from '@mui/material';
3+
import { ExtendedReserveIncentiveResponse } from 'src/hooks/useMerklIncentives';
44

55
import { FormattedNumber } from '../primitives/FormattedNumber';
66
import { Link } from '../primitives/Link';
77
import { Row } from '../primitives/Row';
88
import { TokenIcon } from '../primitives/TokenIcon';
99
import { getSymbolMap } from './IncentivesTooltipContent';
1010

11-
export const ZkSyncIgniteIncentivesTooltipContent = ({
12-
zkSyncIgniteIncentives,
11+
export const MerklIncentivesTooltipContent = ({
12+
merklIncentives,
1313
}: {
14-
zkSyncIgniteIncentives: ExtendedReserveIncentiveResponse;
14+
merklIncentives: ExtendedReserveIncentiveResponse;
1515
}) => {
16+
const theme = useTheme();
17+
1618
const typographyVariant = 'secondary12';
1719

18-
const zkSyncIgniteIncentivesFormatted = getSymbolMap(zkSyncIgniteIncentives);
20+
const merklIncentivesFormatted = getSymbolMap(merklIncentives);
1921

2022
return (
2123
<Box
@@ -26,31 +28,32 @@ export const ZkSyncIgniteIncentivesTooltipContent = ({
2628
flexDirection: 'column',
2729
}}
2830
>
29-
<img src={`/icons/other/zksync-ignite.svg`} width="100px" height="40px" alt="" />
31+
<img
32+
src={
33+
theme.palette.mode === 'dark'
34+
? `/icons/other/merkl-white.svg`
35+
: `/icons/other/merkl-black.svg`
36+
}
37+
width="100px"
38+
height="40px"
39+
alt=""
40+
/>
3041

3142
<Typography variant="caption" color="text.primary" mb={3}>
32-
<Trans>Eligible for the ZKSync Ignite program.</Trans>
43+
<Trans>Eligible for incentives through Merkl.</Trans>
3344
</Typography>
3445

3546
<Typography variant="caption" color="text.secondary" mb={3}>
3647
<Trans>
37-
This is a program initiated and implemented by the decentralised ZKSync community. Aave
38-
Labs does not guarantee the program and accepts no liability.
39-
</Trans>{' '}
40-
<Link
41-
href={'https://zksyncignite.xyz/'}
42-
sx={{ textDecoration: 'underline' }}
43-
variant="caption"
44-
color="text.secondary"
45-
>
46-
Learn more
47-
</Link>
48+
This is a program initiated by the Aave DAO and implemented by Merkl. Aave Labs does not
49+
guarantee the program and accepts no liability.
50+
</Trans>
4851
</Typography>
4952

5053
<Typography variant="caption" color="text.secondary" mb={3}>
51-
<Trans>ZKSync Ignite Program rewards are claimed through the</Trans>{' '}
54+
<Trans>Merkl rewards are claimed through the</Trans>{' '}
5255
<Link
53-
href="https://app.zksyncignite.xyz/users/"
56+
href="https://app.merkl.xyz/"
5457
sx={{ textDecoration: 'underline' }}
5558
variant="caption"
5659
color="text.secondary"
@@ -59,9 +62,9 @@ export const ZkSyncIgniteIncentivesTooltipContent = ({
5962
</Link>
6063
{'.'}
6164
</Typography>
62-
{zkSyncIgniteIncentives.customMessage ? (
65+
{merklIncentives.customMessage ? (
6366
<Typography variant="caption" color="text.strong" mb={3}>
64-
<Trans>{zkSyncIgniteIncentives.customMessage}</Trans>
67+
<Trans>{merklIncentives.customMessage}</Trans>
6568
</Typography>
6669
) : null}
6770

@@ -77,20 +80,18 @@ export const ZkSyncIgniteIncentivesTooltipContent = ({
7780
}}
7881
>
7982
<TokenIcon
80-
aToken={zkSyncIgniteIncentivesFormatted.aToken}
81-
symbol={zkSyncIgniteIncentivesFormatted.tokenIconSymbol}
83+
aToken={merklIncentivesFormatted.aToken}
84+
symbol={merklIncentivesFormatted.tokenIconSymbol}
8285
sx={{ fontSize: '20px', mr: 1 }}
8386
/>
84-
<Typography variant={typographyVariant}>
85-
{zkSyncIgniteIncentivesFormatted.symbol}
86-
</Typography>
87+
<Typography variant={typographyVariant}>{merklIncentivesFormatted.symbol}</Typography>
8788
</Box>
8889
}
8990
width="100%"
9091
>
9192
<Box sx={{ display: 'inline-flex', alignItems: 'center' }}>
9293
<FormattedNumber
93-
value={+zkSyncIgniteIncentivesFormatted.incentiveAPR}
94+
value={+merklIncentivesFormatted.incentiveAPR}
9495
percent
9596
variant={typographyVariant}
9697
/>
Lines changed: 80 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
import { ProtocolAction } from '@aave/contract-helpers';
22
import { ReserveIncentiveResponse } from '@aave/math-utils/dist/esm/formatters/incentive/calculate-reserve-incentives';
3-
import { AaveV3ZkSync } from '@bgd-labs/aave-address-book';
3+
import {
4+
AaveV3Arbitrum,
5+
AaveV3Avalanche,
6+
AaveV3Base,
7+
AaveV3BNB,
8+
AaveV3Celo,
9+
AaveV3Ethereum,
10+
AaveV3EthereumEtherFi,
11+
AaveV3EthereumLido,
12+
AaveV3Gnosis,
13+
AaveV3Linea,
14+
AaveV3Metis,
15+
AaveV3Optimism,
16+
AaveV3Polygon,
17+
AaveV3Scroll,
18+
AaveV3Soneium,
19+
AaveV3Sonic,
20+
} from '@bgd-labs/aave-address-book';
421
import { useQuery } from '@tanstack/react-query';
5-
import { CustomMarket } from 'src/ui-config/marketsConfig';
622
import { Address } from 'viem';
723

824
enum OpportunityAction {
@@ -28,31 +44,59 @@ type MerklOpportunity = {
2844
dailyRewards: number;
2945
tags: [];
3046
id: string;
31-
tokens: [
32-
{
33-
id: string;
34-
name: string;
35-
chainId: number;
36-
address: Address;
37-
decimals: number;
38-
icon: string;
39-
verified: boolean;
40-
isTest: boolean;
41-
price: number;
42-
symbol: string;
43-
}
44-
];
47+
tokens: {
48+
id: string;
49+
name: string;
50+
chainId: number;
51+
address: Address;
52+
decimals: number;
53+
icon: string;
54+
verified: boolean;
55+
isTest: boolean;
56+
price: number;
57+
symbol: string;
58+
}[];
4559
};
4660

4761
export type ExtendedReserveIncentiveResponse = ReserveIncentiveResponse & {
4862
customMessage: string;
4963
customForumLink: string;
5064
};
5165

52-
const url = 'https://api.merkl.xyz/v4/opportunities?tags=zksync&mainProtocolId=aave'; // Merkl API for ZK Ignite opportunities
66+
const allAaveAssets = [
67+
AaveV3Ethereum.ASSETS,
68+
AaveV3EthereumLido.ASSETS,
69+
AaveV3EthereumEtherFi.ASSETS,
70+
AaveV3Base.ASSETS,
71+
AaveV3Arbitrum.ASSETS,
72+
AaveV3Avalanche.ASSETS,
73+
AaveV3Sonic.ASSETS,
74+
AaveV3Optimism.ASSETS,
75+
AaveV3Polygon.ASSETS,
76+
AaveV3Metis.ASSETS,
77+
AaveV3Gnosis.ASSETS,
78+
AaveV3BNB.ASSETS,
79+
AaveV3Scroll.ASSETS,
80+
AaveV3Linea.ASSETS,
81+
AaveV3Celo.ASSETS,
82+
AaveV3Soneium.ASSETS,
83+
];
5384

54-
const rewardToken = AaveV3ZkSync.ASSETS.ZK.UNDERLYING;
55-
const rewardTokenSymbol = 'ZK';
85+
const getUnderlyingAndAToken = (assets: {
86+
[key: string]: {
87+
UNDERLYING: Address;
88+
A_TOKEN: Address;
89+
};
90+
}) => {
91+
return Object.entries(assets).flatMap(([, asset]) => [
92+
asset.UNDERLYING.toLowerCase(),
93+
asset.A_TOKEN.toLowerCase(),
94+
]);
95+
};
96+
97+
const whitelistedRewardTokens = allAaveAssets.flatMap((assets) => getUnderlyingAndAToken(assets));
98+
99+
const MERKL_ENDPOINT = 'https://api.merkl.xyz/v4/opportunities?mainProtocolId=aave'; // Merkl API
56100

57101
const checkOpportunityAction = (
58102
opportunityAction: OpportunityAction,
@@ -68,7 +112,7 @@ const checkOpportunityAction = (
68112
}
69113
};
70114

71-
export const useZkSyncIgniteIncentives = ({
115+
export const useMerklIgniteIncentives = ({
72116
market,
73117
rewardedAsset,
74118
protocolAction,
@@ -79,15 +123,11 @@ export const useZkSyncIgniteIncentives = ({
79123
}) => {
80124
return useQuery({
81125
queryFn: async () => {
82-
if (market === CustomMarket.proto_zksync_v3) {
83-
const response = await fetch(url);
84-
const merklOpportunities: MerklOpportunity[] = await response.json();
85-
return merklOpportunities;
86-
} else {
87-
return [];
88-
}
126+
const response = await fetch(`${MERKL_ENDPOINT}`);
127+
const merklOpportunities: MerklOpportunity[] = await response.json();
128+
return merklOpportunities;
89129
},
90-
queryKey: ['zkIgniteIncentives', market],
130+
queryKey: ['merklIncentives', market],
91131
staleTime: 1000 * 60 * 5,
92132
select: (merklOpportunities) => {
93133
const opportunities = merklOpportunities.filter(
@@ -108,12 +148,22 @@ export const useZkSyncIgniteIncentives = ({
108148
return null;
109149
}
110150

151+
if (opportunity.apr <= 0) {
152+
return null;
153+
}
154+
111155
const apr = opportunity.apr / 100;
112156

157+
const rewardToken = opportunity.tokens[opportunity.tokens.length - 1];
158+
159+
if (!whitelistedRewardTokens.includes(rewardToken.address.toLowerCase())) {
160+
return null;
161+
}
162+
113163
return {
114164
incentiveAPR: apr.toString(),
115-
rewardTokenAddress: rewardToken,
116-
rewardTokenSymbol: rewardTokenSymbol,
165+
rewardTokenAddress: rewardToken.address,
166+
rewardTokenSymbol: rewardToken.symbol,
117167
} as ExtendedReserveIncentiveResponse;
118168
},
119169
});

src/locales/el/messages.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/locales/en/messages.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)