Skip to content

Commit 4311469

Browse files
committed
ux: harmonize showing claimable rewards across tools
now all tools apart from opportunities tool show all claimable rewards including extra token rewards
1 parent 83e8f86 commit 4311469

File tree

5 files changed

+79
-45
lines changed

5 files changed

+79
-45
lines changed

projects/convex/TODO.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@
66

77
## Minor
88

9-
- Claim rewards:
10-
- Check that extra tokens are claimed correctly
11-
- src/helpers/rewards.ts: format extra rewards with correct decimals
12-
- Check that extra token rewards are displayed correctly
139
- Warning for cvxCRV depegging (see [here](https://www.defiwars.xyz/projects/convex) and [here](https://d.pr/i/gFtnBU))
1410
- How to check CRV and CVX staking APR > https://discord.com/channels/820795644494610432/864157305566527508/1154349279763234868
1511

1612
## Future
1713

14+
- Reduce the number of calls to the blockchain in getClaimableRewards using multicall
1815
- Optionally have the claimRewards tool to lock CVX (see ClaimZap.sol)
1916
- In deposit tools, if the user does not have enough tokens, we could suggest him to deposit into Curve first by showing them the URL to the Curve pool/lending vault page
2017
- In `getConvexLiquidityPool` and `getConvexLendingVault`, specify the amounts of claimable rewards (https://d.pr/i/IUQMoB)

projects/convex/src/functions/getBestYieldOpportunitiesForUnderlyingToken.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ export async function getBestYieldOpportunitiesForUnderlyingToken(
9090
// Enrich the opportunities
9191
const enrichedOpportunities: EnrichedConvexToken[] = [];
9292
for (const poolOrVault of firstNOpportunities) {
93-
const enriched = await enrichConvexToken(poolOrVault, provider, apys[poolOrVault.id], account);
93+
// Get user balance but do not get claimable rewards
94+
const enriched = await enrichConvexToken(poolOrVault, provider, apys[poolOrVault.id], account, false);
9495
enrichedOpportunities.push(enriched);
9596
}
9697

projects/convex/src/functions/getMyPositionsPortfolio.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,22 @@ export async function getMyPositionsPortfolio({ chainName, positionTypes, minTvl
191191
// Add claimable rewards if any
192192
if (balance.claimableRewards) {
193193
const rewards = balance.claimableRewards;
194-
if (rewards.crv > 0n || rewards.cvx > 0n) {
195-
subParts.push(` - claimable:`);
196-
if (rewards.crv > 0n) {
197-
subParts.push(` ${rewards.crvFormatted} CRV`);
198-
}
199-
if (rewards.cvx > 0n) {
200-
if (rewards.crv > 0n) subParts.push(',');
201-
subParts.push(` ${rewards.cvxFormatted} CVX`);
202-
}
194+
const rewardsParts: string[] = [];
195+
if (rewards.crv > 0n) {
196+
rewardsParts.push(`${rewards.crvFormatted} CRV`);
197+
}
198+
if (rewards.cvx > 0n) {
199+
rewardsParts.push(`${rewards.cvxFormatted} CVX`);
200+
}
201+
if (rewards.extraRewards && rewards.extraRewards.length > 0) {
202+
rewards.extraRewards.forEach((r) => {
203+
if (r.amount > 0n) {
204+
rewardsParts.push(`${r.formatted} ${r.symbol}`);
205+
}
206+
});
207+
}
208+
if (rewardsParts.length > 0) {
209+
subParts.push(` - claimable: ${rewardsParts.join(', ')}`);
203210
}
204211
}
205212
if (ct.isBrokenOrShutdown) {

projects/convex/src/helpers/poolAndVaults.ts

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,13 @@ export type EnrichedConvexToken = {
7373
* - pass the APY object to compute the APR and APY (takes 1
7474
* request to the blockchain)
7575
*/
76-
export async function enrichConvexToken(obj: Pool | LendingVault, provider: PublicClient, apyFromApi?: Apy, account?: `0x${string}`): Promise<EnrichedConvexToken> {
76+
export async function enrichConvexToken(
77+
obj: Pool | LendingVault,
78+
provider: PublicClient,
79+
apyFromApi?: Apy,
80+
account?: `0x${string}`,
81+
withRewards: boolean = true,
82+
): Promise<EnrichedConvexToken> {
7783
// Determine the type of token
7884
let type: 'LP' | 'LV';
7985
if (isPool(obj)) {
@@ -142,7 +148,7 @@ export async function enrichConvexToken(obj: Pool | LendingVault, provider: Publ
142148
} catch (error) {
143149
console.warn(`Failed to fetch convex token balances for pool ${obj.convexPoolData.id}:`, error);
144150
}
145-
if (result.userBalances && result.userBalances.staked > 0n) {
151+
if (withRewards && result.userBalances && result.userBalances.staked > 0n) {
146152
try {
147153
result.userBalances.claimableRewards = await getClaimableRewards(provider, obj.convexPoolData.crvRewards, account, true);
148154
} catch (error) {
@@ -234,25 +240,21 @@ export function formatConvexToken(ct: EnrichedConvexToken, includeIntro: boolean
234240
const rewards = ct.userBalances.claimableRewards;
235241
const rewardsParts: string[] = [];
236242

237-
if (rewards.crv > 0n || rewards.cvx > 0n) {
238-
rewardsParts.push(' - You can claim rewards:');
239-
if (rewards.crv > 0n) {
240-
rewardsParts.push(` ${rewards.crvFormatted} CRV`);
241-
}
242-
if (rewards.cvx > 0n) {
243-
if (rewards.crv > 0n) rewardsParts.push(' and');
244-
rewardsParts.push(` ${rewards.cvxFormatted} CVX`);
245-
}
246-
247-
// Add extra rewards if any
248-
if (rewards.extraRewards && rewards.extraRewards.length > 0) {
249-
const extraCount = rewards.extraRewards.filter((r) => r.amount > 0n).length;
250-
if (extraCount > 0) {
251-
rewardsParts.push(` (plus ${extraCount} other token${extraCount > 1 ? 's' : ''})`);
243+
if (rewards.crv > 0n) {
244+
rewardsParts.push(`${rewards.crvFormatted} CRV`);
245+
}
246+
if (rewards.cvx > 0n) {
247+
rewardsParts.push(`${rewards.cvxFormatted} CVX`);
248+
}
249+
if (rewards.extraRewards && rewards.extraRewards.length > 0) {
250+
rewards.extraRewards.forEach((r) => {
251+
if (r.amount > 0n) {
252+
rewardsParts.push(`${r.formatted} ${r.symbol}`);
252253
}
253-
}
254-
255-
parts.push(rewardsParts.join(''));
254+
});
255+
}
256+
if (rewardsParts.length > 0) {
257+
parts.push(` - You can claim rewards: ${rewardsParts.join(', ')}`);
256258
}
257259
}
258260
}
@@ -302,15 +304,22 @@ export function formatConvexTokenShort(ct: EnrichedConvexToken): string {
302304
// Add claimable rewards if any
303305
if (ct.userBalances.claimableRewards) {
304306
const rewards = ct.userBalances.claimableRewards;
305-
if (rewards.crv > 0n || rewards.cvx > 0n) {
306-
parts.push(` - claimable:`);
307-
if (rewards.crv > 0n) {
308-
parts.push(` ${rewards.crvFormatted} CRV`);
309-
}
310-
if (rewards.cvx > 0n) {
311-
if (rewards.crv > 0n) parts.push(',');
312-
parts.push(` ${rewards.cvxFormatted} CVX`);
313-
}
307+
const rewardsParts: string[] = [];
308+
if (rewards.crv > 0n) {
309+
rewardsParts.push(`${rewards.crvFormatted} CRV`);
310+
}
311+
if (rewards.cvx > 0n) {
312+
rewardsParts.push(`${rewards.cvxFormatted} CVX`);
313+
}
314+
if (rewards.extraRewards && rewards.extraRewards.length > 0) {
315+
rewards.extraRewards.forEach((r) => {
316+
if (r.amount > 0n) {
317+
rewardsParts.push(`${r.formatted} ${r.symbol}`);
318+
}
319+
});
320+
}
321+
if (rewardsParts.length > 0) {
322+
parts.push(` - claimable: ${rewardsParts.join(', ')}`);
314323
}
315324
}
316325
} else if (ct.userBalances.underlying > 0n) {

projects/convex/src/helpers/rewards.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Functions to fetch claimable rewards from Convex staking positions
33
*/
44

5-
import { PublicClient, formatUnits } from 'viem';
5+
import { PublicClient, formatUnits, erc20Abi } from 'viem';
66
import { baseRewardPoolAbi } from '../abis/baseRewardPoolAbi';
77
import { cvxMiningAbi } from '../abis/cvxMiningAbi';
88
import { CVX_MINING_CONTRACT_ADDRESS } from '../constants';
@@ -14,6 +14,8 @@ export interface ClaimableRewards {
1414
cvxFormatted: string; // Human-readable CVX amount
1515
extraRewards?: Array<{
1616
token: `0x${string}`;
17+
symbol: string;
18+
decimals: number;
1719
amount: bigint;
1820
formatted: string;
1921
}>;
@@ -23,6 +25,8 @@ export interface ClaimableRewards {
2325
* Fetch the amount of claimable CRV, CVX and extra tokens
2426
* rewards for a user's staked position in a specific Convex
2527
* pool/vault.
28+
*
29+
* TODO: Use multicall to reduce the number of calls
2630
*/
2731
export async function getClaimableRewards(
2832
provider: PublicClient,
@@ -78,6 +82,20 @@ export async function getClaimableRewards(
7882
functionName: 'rewardToken',
7983
})) as `0x${string}`;
8084

85+
// Get the reward token symbol
86+
const rewardSymbol = (await provider.readContract({
87+
address: rewardToken,
88+
abi: erc20Abi,
89+
functionName: 'symbol',
90+
})) as string;
91+
92+
// Get the reward token decimals
93+
const rewardTokenDecimals = (await provider.readContract({
94+
address: rewardToken,
95+
abi: erc20Abi,
96+
functionName: 'decimals',
97+
})) as number;
98+
8199
// Get earned amount for this extra reward
82100
const earnedExtra = (await provider.readContract({
83101
address: extraRewardPoolAddress,
@@ -89,8 +107,10 @@ export async function getClaimableRewards(
89107
if (earnedExtra > 0n) {
90108
extraRewards.push({
91109
token: rewardToken,
110+
symbol: rewardSymbol,
111+
decimals: rewardTokenDecimals,
92112
amount: earnedExtra,
93-
formatted: formatUnits(earnedExtra, 18),
113+
formatted: formatUnits(earnedExtra, rewardTokenDecimals),
94114
});
95115
}
96116
}

0 commit comments

Comments
 (0)