Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Fixed issues with max rewards + improved rewards section for audits #549

Merged
merged 5 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/web/src/components/VaultCard/VaultCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export const VaultCard = ({
? millify(totalPaidOutOnAudit?.usd ?? 0)
: showIntended
? millify(vault.amountsInfo?.competitionIntendedAmount?.deposited.usd ?? 0)
: millify(vault.amountsInfo?.depositedAmount.usd ?? 0)}
: millify(vault.amountsInfo?.maxRewardAmount.usd ?? 0)}
Copy link

Choose a reason for hiding this comment

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

Image description CodeRabbit

The change from depositedAmount to maxRewardAmount seems appropriate given the context. However, it's important to ensure that maxRewardAmount is always defined and has a valid value before this operation to avoid potential runtime errors or incorrect calculations.

- : millify(vault.amountsInfo?.maxRewardAmount.usd ?? 0)}
+ : vault.amountsInfo?.maxRewardAmount ? millify(vault.amountsInfo.maxRewardAmount.usd) : 0}

This change ensures that millify function is only called when maxRewardAmount is not null or undefined.

</h3>
</WithTooltip>
<div className="sub-value">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IVault, IVulnerabilitySeverity } from "@hats-finance/shared";
import { Pill, VaultNftRewardCard } from "components";
import { IVault, IVulnerabilitySeverity, IVulnerabilitySeverityV2 } from "@hats-finance/shared";
import InfoIcon from "@mui/icons-material/InfoOutlined";
import { Pill, VaultNftRewardCard, WithTooltip } from "components";
import { useSeverityRewardInfo } from "hooks/severities/useSeverityRewardInfo";
import { useTranslation } from "react-i18next";
import { formatNumber } from "utils";
Expand All @@ -14,20 +15,40 @@ interface VaultSeverityRewardCardProps {

export function VaultSeverityRewardCard({ vault, severity, severityIndex, noNft = false }: VaultSeverityRewardCardProps) {
const { t } = useTranslation();
const { rewardPercentage, rewardPrice, rewardColor } = useSeverityRewardInfo(vault, severityIndex);
const { rewardPercentage, rewardPrice, rewardCap, rewardColor } = useSeverityRewardInfo(vault, severityIndex);

const severityName = severity?.name.toLowerCase().replace("severity", "") ?? "";
const showCap = vault.version === "v2" && vault.description?.severities.some((sev) => !!sev.capAmount);
Comment on lines +18 to +21
Copy link

Choose a reason for hiding this comment

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

Image description CodeRabbit

The useSeverityRewardInfo hook now returns a new property rewardCap. This is used to display the maximum reward cap for each severity level. The condition showCap checks if the vault version is "v2" and if there's a cap amount defined for any severity. If true, an additional column will be displayed in the UI to show the cap amount. This is a good approach to handle different versions of the vault and only show relevant information based on the version.

However, I noticed that you're using optional chaining (?.) on severity, which means it could potentially be undefined. If severity is undefined, severityName would be an empty string. Make sure this case is handled properly in your UI.


return (
<StyledVaultSeverityRewardCard color={rewardColor} noNft={noNft}>
<Pill isSeverity transparent textColor={rewardColor} text={severityName} />
<StyledVaultSeverityRewardCard columns={2 + (noNft ? 0 : 1) + (showCap ? 1 : 0)} color={rewardColor}>
<div className="severity-name">
<Pill isSeverity transparent textColor={rewardColor} text={severityName} />
</div>
<div className="severity-prize">
<div>
<span>{`${rewardPercentage.toFixed(2)}%`}</span>
<span className="tiny">&nbsp;{t("ofVault")}&nbsp;</span>
<span className="tiny">&nbsp;{t("ofRewards")}&nbsp;</span>
</div>
<span className="price">~{`$${formatNumber(rewardPrice)}`}</span>
</div>
{showCap && (
<>
{(severity as IVulnerabilitySeverityV2).capAmount ? (
<WithTooltip text={t("maxRewardCapExplanation")}>
<div className="severity-prize">
<div className="title-container">
<span className="tiny">{t("maxRewardCap")}</span>
<InfoIcon fontSize="small" />
</div>
<span className="price">~{`$${formatNumber(rewardCap)}`}</span>
</div>
</WithTooltip>
) : (
<div />
)}
</>
)}
Comment on lines 23 to +51
Copy link

Choose a reason for hiding this comment

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

Image description CodeRabbit

This section of code handles the rendering of the severity reward card. It includes the severity name, reward percentage, reward price, and optionally the reward cap and NFT reward card.

The reward cap is only shown if showCap is true, which is determined by the vault version and whether a cap amount is defined for any severity. The tooltip with the explanation of the maximum reward cap is a nice touch for user understanding.

One potential issue here is the casting of severity to IVulnerabilitySeverityV2 at line 37. This assumes that if showCap is true, severity must be of type IVulnerabilitySeverityV2. However, TypeScript does not enforce this at runtime, so there could be a potential type error if severity is not actually of type IVulnerabilitySeverityV2. You might want to add a runtime check before casting to avoid potential errors.

- {(severity as IVulnerabilitySeverityV2).capAmount ? (
+ {('capAmount' in severity && severity.capAmount) ? (

This change uses the in operator to check if the capAmount property exists in severity before accessing it, providing an extra layer of safety.

{!noNft && (
<div className="severity-nft">
<VaultNftRewardCard vault={vault} severity={severity} type="tiny" />
Expand Down
31 changes: 22 additions & 9 deletions packages/web/src/components/VaultSeverityRewardCard/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import styled, { css } from "styled-components";
import { getSpacing } from "styles";
import { breakpointsDefinition } from "styles/breakpoints.styles";

export const StyledVaultSeverityRewardCard = styled.div<{ color: string; noNft: boolean }>(
({ color, noNft }) => css`
export const StyledVaultSeverityRewardCard = styled.div<{ color: string; columns: number }>(
({ color, columns }) => css`
display: grid;
grid-template-columns: ${noNft ? "3fr 4fr" : "1fr 1fr 1fr"};
grid-template-columns: ${columns === 2 ? "3fr 4fr" : columns === 3 ? "1fr 1fr 1fr" : "1fr 1fr 1fr 1fr"};
align-items: center;
justify-content: space-between;
gap: ${getSpacing(1)};
gap: ${getSpacing(2)};

.severity-name,
.severity-prize,
Expand All @@ -24,11 +24,16 @@ export const StyledVaultSeverityRewardCard = styled.div<{ color: string; noNft:
}

@media (max-width: ${breakpointsDefinition.mediumMobile}) {
grid-template-columns: ${noNft ? "1fr 1fr" : "2fr 1fr 1fr"};
grid-template-columns: ${columns === 2 ? "1fr 1fr" : columns === 3 ? "1fr 1fr 1fr" : "1fr 1fr 1fr 1fr"};
}

@media (max-width: ${breakpointsDefinition.smallMobile}) {
grid-template-columns: ${noNft ? "1fr 1fr" : "4fr 4fr 3fr"};
grid-template-columns: ${columns === 2 ? "1fr" : columns === 3 ? "1fr 1fr" : "1fr 1fr"};

.severity-name {
grid-column-start: 1;
grid-column-end: ${columns};
}
}

.severity-name {
Expand All @@ -39,10 +44,17 @@ export const StyledVaultSeverityRewardCard = styled.div<{ color: string; noNft:

.severity-prize {
font-weight: 700;
flex-direction: column;
align-items: flex-end;

@media (max-width: ${breakpointsDefinition.smallMobile}) {
align-items: center;
}

@media (max-width: ${breakpointsDefinition.mediumMobile}) {
flex-direction: column;
align-items: flex-end;
.title-container {
display: flex;
align-items: center;
gap: ${getSpacing(0.2)};
}

.tiny {
Expand All @@ -51,6 +63,7 @@ export const StyledVaultSeverityRewardCard = styled.div<{ color: string; noNft:
}

.price {
font-size: var(--small);
color: ${color};
font-weight: 700;
}
Expand Down
25 changes: 12 additions & 13 deletions packages/web/src/hooks/severities/useSeverityRewardInfo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { formatUnits } from "ethers/lib/utils";
import { useVaultsTotalPrices } from "hooks/vaults/useVaultsTotalPrices";
import { IVault } from "types";
import { generateColorsArrayInBetween } from "utils/colors.utils";
Expand All @@ -15,60 +14,60 @@ export const getSeveritiesColorsArray = (vault: IVault | undefined): string[] =>
export function useSeverityRewardInfo(vault: IVault | undefined, severityIndex: number) {
const { totalPrices } = useVaultsTotalPrices(vault ? vault.multipleVaults ?? [vault] : []);

if (!vault || !vault.description) return { rewardPrice: 0, rewardPercentage: 0, rewardColor: INITIAL_SEVERITY_COLOR };
if (!vault || !vault.description)
return { rewardPrice: 0, rewardPercentage: 0, rewardCap: 0, rewardColor: INITIAL_SEVERITY_COLOR };

const isAudit = vault.description && vault.description["project-metadata"].type === "audit";
const showIntendedAmounts = vault.amountsInfo?.showCompetitionIntendedAmount ?? false;
const SEVERITIES_COLORS = getSeveritiesColorsArray(vault);

if (vault.version === "v2") {
const severity = vault.description.severities[severityIndex];
if (!severity) return { rewardPrice: 0, rewardPercentage: 0, rewardColor: INITIAL_SEVERITY_COLOR };
if (!severity) return { rewardPrice: 0, rewardPercentage: 0, rewardCap: 0, rewardColor: INITIAL_SEVERITY_COLOR };

const sumTotalPrices = Object.values(totalPrices).reduce((a, b = 0) => a + b, 0);
// const maxBountyPercentage = Number(vault.maxBounty) / 10000; // Number between 0 and 1;
// TODO: remove this when we have the new vault contract version
const maxBountyPercentage = Number(isAudit ? 10000 : vault.maxBounty) / 10000;
const rewardPercentage = +severity.percentage * maxBountyPercentage;
const rewardPercentage = +severity.percentage;

let rewardPrice: number = 0;
let rewardCap: number = 0;
if (vault.multipleVaults && sumTotalPrices) {
rewardPrice = sumTotalPrices * (rewardPercentage / 100);
} else if (vault.amountsInfo?.tokenPriceUsd) {
rewardPrice =
(showIntendedAmounts
? vault.amountsInfo.competitionIntendedAmount?.deposited.tokens ?? 0
: Number(formatUnits(vault.honeyPotBalance, vault.stakingTokenDecimals))) *
: vault.amountsInfo.maxRewardAmount.tokens) *
(rewardPercentage / 100) *
vault.amountsInfo?.tokenPriceUsd;
rewardCap = (severity.capAmount ?? 0) * vault.amountsInfo?.tokenPriceUsd;
}

const orderedSeverities = vault.description.severities.map((severity) => severity.percentage).sort((a, b) => a - b);
const rewardColor: string = SEVERITIES_COLORS[orderedSeverities.indexOf(severity.percentage) ?? 0];

return { rewardPrice, rewardPercentage, rewardColor };
return { rewardPrice, rewardPercentage, rewardCap, rewardColor };
} else {
Comment on lines +17 to 48
Copy link

Choose a reason for hiding this comment

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

Image description CodeRabbit

The changes in this section seem to be well thought out. The addition of the rewardCap property and its calculation based on the severity's cap amount is a good improvement. However, there seems to be a potential issue with the calculation of rewardPrice. If vault.multipleVaults is false and vault.amountsInfo?.tokenPriceUsd is undefined, rewardPrice will remain 0. This could lead to incorrect calculations downstream. Consider adding error handling or a default value for vault.amountsInfo?.tokenPriceUsd.

- let rewardPrice: number = 0;
+ let rewardPrice: number = vault.amountsInfo?.tokenPriceUsd ?? DEFAULT_TOKEN_PRICE;

const severity = vault.description.severities[severityIndex];
if (!severity) return { rewardPrice: 0, rewardPercentage: 0, rewardColor: INITIAL_SEVERITY_COLOR };
if (!severity) return { rewardPrice: 0, rewardPercentage: 0, rewardCap: 0, rewardColor: INITIAL_SEVERITY_COLOR };

const sumTotalPrices = Object.values(totalPrices).reduce((a, b = 0) => a + b, 0);
const rewardPercentage = (Number(vault.rewardsLevels[severity.index]) / 10000) * 100;

let rewardPrice: number = 0;
let rewardCap: number = 0;
if (vault.multipleVaults && sumTotalPrices) {
rewardPrice = sumTotalPrices * (rewardPercentage / 100);
} else if (vault.amountsInfo?.tokenPriceUsd) {
rewardPrice =
(showIntendedAmounts
? vault.amountsInfo.competitionIntendedAmount?.deposited.tokens ?? 0
: Number(formatUnits(vault.honeyPotBalance, vault.stakingTokenDecimals))) *
: vault.amountsInfo.maxRewardAmount.tokens) *
(rewardPercentage / 100) *
vault.amountsInfo?.tokenPriceUsd;
}

const orderedSeverities = vault.description.severities.map((severity) => severity.index).sort((a, b) => a - b);
const rewardColor: string = SEVERITIES_COLORS[orderedSeverities.indexOf(severity.index) ?? 0];

return { rewardPrice, rewardPercentage, rewardColor };
return { rewardPrice, rewardPercentage, rewardCap, rewardColor };
Comment on lines 49 to +71
Copy link

Choose a reason for hiding this comment

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

Image description CodeRabbit

Similar to the previous comment, consider adding error handling or a default value for vault.amountsInfo?.tokenPriceUsd when calculating rewardPrice.

- let rewardPrice: number = 0;
+ let rewardPrice: number = vault.amountsInfo?.tokenPriceUsd ?? DEFAULT_TOKEN_PRICE;

}
}
33 changes: 25 additions & 8 deletions packages/web/src/hooks/subgraph/vaults/parser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { formatUnits } from "@ethersproject/units";
import { IMaster, IPayoutGraph, IUserNft, IVault } from "@hats-finance/shared";
import { BigNumber } from "ethers";
import { BigNumber, ethers } from "ethers";

Choose a reason for hiding this comment

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

Image description CodeRabbit

The import statement has been modified to include ethers from "ethers" package. This is a good change as it allows the use of ethers.constants.MaxUint256 in the code, which is a constant that represents the maximum possible value for an unsigned 256-bit integer. This is used later in the code to check if the governance and hacker reward splits are set to their maximum values.

- import { BigNumber } from "ethers";
+ import { BigNumber, ethers } from "ethers";

import { appChains } from "settings";

export const parseMasters = (masters: IMaster[], chainId: number) => {
Expand Down Expand Up @@ -49,14 +49,32 @@ export const populateVaultsWithPricing = (vaults: IVault[], tokenPrices: number[
const isTestnet = appChains[vault.chainId].chain.testnet;
const tokenPrice: number = isTestnet ? 1387.65 : (tokenPrices && tokenPrices[vault.stakingToken]) ?? 0;
const depositedAmountTokens = Number(formatUnits(vault.honeyPotBalance, vault.stakingTokenDecimals));
const isAudit = vault.description?.["project-metadata"].type === "audit";

const maxRewardFactor = vault.version === "v1" ? +vault.rewardsLevels[vault.rewardsLevels.length - 1] : +vault.maxBounty;
console.log(vault);

const governanceSplit = BigNumber.from(vault.governanceHatRewardSplit).eq(ethers.constants.MaxUint256)
? vault.master.defaultGovernanceHatRewardSplit
: vault.governanceHatRewardSplit;
const hackerHatsSplit = BigNumber.from(vault.hackerHatRewardSplit).eq(ethers.constants.MaxUint256)
? vault.master.defaultHackerHatRewardSplit
: vault.hackerHatRewardSplit;

// In v2 vaults the split sum (immediate, vested, committee) is 100%. So we need to calculate the split factor to get the correct values.
// In v1 this is not a probem. So the factor is 1.
const splitFactor = vault.version === "v1" ? 1 : (10000 - Number(governanceSplit) - Number(hackerHatsSplit)) / 100 / 100;

const governanceFee = Number(governanceSplit) / 100 / 100;
const committeeFee = (Number(vault.committeeRewardSplit) / 100 / 100) * splitFactor;

const maxRewardFactor = 1 - governanceFee - committeeFee;

return {
...vault,
amountsInfo: {
showCompetitionIntendedAmount:
vault.description?.["project-metadata"].type === "audit" &&
isAudit &&
vault.description &&
Comment on lines +52 to +77

Choose a reason for hiding this comment

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

Image description CodeRabbit

The logic for determining whether to show the competition intended amount has been updated. Previously, it was based solely on whether the vault type was "audit". Now, it also checks if the start time of the project is more than 48 hours in the future and if there is an intended competition amount defined. This makes the condition more robust and ensures that the competition intended amount is only shown when it is relevant.

-         showCompetitionIntendedAmount:
-          vault.description?.["project-metadata"].type === "audit" &&
+         showCompetitionIntendedAmount:
+          isAudit &&
           vault.description &&
           vault.description["project-metadata"].starttime &&
           vault.description["project-metadata"].starttime > new Date().getTime() / 1000 + 48 * 3600 && // 48 hours
           !!vault.description?.["project-metadata"].intendedCompetitionAmount &&

vault.description["project-metadata"].starttime &&
vault.description["project-metadata"].starttime > new Date().getTime() / 1000 + 48 * 3600 && // 48 hours
!!vault.description?.["project-metadata"].intendedCompetitionAmount &&
Expand All @@ -69,9 +87,8 @@ export const populateVaultsWithPricing = (vaults: IVault[], tokenPrices: number[
usd: +vault.description?.["project-metadata"].intendedCompetitionAmount * tokenPrice,
},
maxReward: {
tokens: +vault.description?.["project-metadata"].intendedCompetitionAmount * (maxRewardFactor / 100 / 100),
usd:
+vault.description?.["project-metadata"].intendedCompetitionAmount * tokenPrice * (maxRewardFactor / 100 / 100),
tokens: +vault.description?.["project-metadata"].intendedCompetitionAmount * maxRewardFactor,
usd: +vault.description?.["project-metadata"].intendedCompetitionAmount * tokenPrice * maxRewardFactor,
Comment on lines +90 to +91

Choose a reason for hiding this comment

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

Image description CodeRabbit

The calculation of the maximum reward in tokens and USD has been updated. Previously, the maxRewardFactor was divided by 100 twice, effectively dividing it by 10,000. This was likely done because the maxRewardFactor was expressed as a percentage with two decimal places. However, the new code calculates maxRewardFactor differently, so it no longer needs to be divided by 10,000. This change is correct assuming the new calculation of maxRewardFactor is accurate.

-                tokens: +vault.description?.["project-metadata"].intendedCompetitionAmount * (maxRewardFactor / 100 / 100),
-                usd:
-                  +vault.description?.["project-metadata"].intendedCompetitionAmount * tokenPrice * (maxRewardFactor / 100 / 100),
+                tokens: +vault.description?.["project-metadata"].intendedCompetitionAmount * maxRewardFactor,
+                usd: +vault.description?.["project-metadata"].intendedCompetitionAmount * tokenPrice * maxRewardFactor,

},
}
: undefined,
Expand All @@ -80,8 +97,8 @@ export const populateVaultsWithPricing = (vaults: IVault[], tokenPrices: number[
usd: depositedAmountTokens * tokenPrice,
},
maxRewardAmount: {
tokens: depositedAmountTokens * (maxRewardFactor / 100 / 100),
usd: depositedAmountTokens * tokenPrice * (maxRewardFactor / 100 / 100),
tokens: depositedAmountTokens * maxRewardFactor,
usd: depositedAmountTokens * tokenPrice * maxRewardFactor,
Comment on lines +100 to +101

Choose a reason for hiding this comment

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

Image description CodeRabbit

The calculation of the maximum reward amount in tokens and USD has been updated in the same way as the maximum reward. The changes are correct given the new calculation of maxRewardFactor.

-          tokens: depositedAmountTokens * (maxRewardFactor / 100 / 100),
-          usd: depositedAmountTokens * tokenPrice * (maxRewardFactor / 100 / 100),
+          tokens: depositedAmountTokens * maxRewardFactor,
+          usd: depositedAmountTokens * tokenPrice * maxRewardFactor,

},
},
} as IVault;
Expand Down
3 changes: 3 additions & 0 deletions packages/web/src/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,9 @@
"goToProjectWebsite": "Go to project website",
"doYouWantToGoToProjectWebsite": "Do you want to go to project website? \n ({{website}})",
"yesGo": "Yes, go",
"ofRewards": "of rewards",
"maxRewardCap": "Max reward cap",
"maxRewardCapExplanation": "This is the maximum amount that will be paid for a single submission.",
"clearSubmission": "Clear submission",
"clearSubmissionExplanation": "Are you sure you want to clear this submission? \n\n This will remove all the information of the submission.",
"clearForm": "Clear form",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,27 @@ type VaultRewardsSectionProps = {

export const VaultRewardsSection = ({ vault }: VaultRewardsSectionProps) => {
const { t } = useTranslation();
const isAudit = vault.description && vault.description["project-metadata"].type === "audit";

const isAudit = vault.description && vault.description["project-metadata"].type === "audit";
const showIntended = vault.amountsInfo?.showCompetitionIntendedAmount ?? false;

return (
<StyledRewardsSection showIntended={showIntended}>
<StyledRewardsSection showIntended={showIntended} isAudit={!!isAudit}>
<h2>{t("rewards")}</h2>
<div className="rewards-containers mt-4">
<div className="amounts">
<div className="card amount-card">
<h4 className="title">{showIntended ? t("intendedDeposits") : t("totalDeposits")}</h4>
{showIntended ? (
<WithTooltip text={t("intendedValueExplanation")}>
<h4 className="value">~${millify(vault.amountsInfo?.competitionIntendedAmount?.deposited.usd ?? 0)}</h4>
</WithTooltip>
) : (
<h4 className="value">~${millify(vault.amountsInfo?.depositedAmount.usd ?? 0)}</h4>
)}
</div>
{!isAudit && (
<div className="card amount-card">
<h4 className="title">{showIntended ? t("intendedDeposits") : t("totalDeposits")}</h4>
{showIntended ? (
<WithTooltip text={t("intendedValueExplanation")}>
<h4 className="value">~${millify(vault.amountsInfo?.competitionIntendedAmount?.deposited.usd ?? 0)}</h4>
</WithTooltip>
) : (
<h4 className="value">~${millify(vault.amountsInfo?.depositedAmount.usd ?? 0)}</h4>
)}
</div>
)}
<div className="card">
<h4 className="title">{t("assetsInVault")}</h4>
<VaultAssetsPillsList vaultData={vault} />
Expand All @@ -44,25 +46,20 @@ export const VaultRewardsSection = ({ vault }: VaultRewardsSectionProps) => {
<h4 className="value">~${millify(vault.amountsInfo?.competitionIntendedAmount?.maxReward.usd ?? 0)}</h4>
</WithTooltip>
) : (
// TODO: In here should be only the max reward amount, not the deposited amount
// Change this once we have the new contract version
<h4 className="value">
~$
{isAudit
? millify(vault.amountsInfo?.depositedAmount.usd ?? 0)
: millify(vault.amountsInfo?.maxRewardAmount.usd ?? 0)}
</h4>
<h4 className="value">~${millify(vault.amountsInfo?.maxRewardAmount.usd ?? 0)}</h4>
)}
</div>
</div>
<div className="division">
<div className="card">
<h4 className="title">{t("rewardsDivision")}</h4>
<div className="chart-container">
<VaultRewardDivision vault={vault} />
{!isAudit && (
<div className="division">
<div className="card">
<h4 className="title">{t("rewardsDivision")}</h4>
<div className="chart-container">
<VaultRewardDivision vault={vault} />
</div>
</div>
</div>
</div>
)}
<div className="severities-rewards">
<div className="card">
<h4 className="title">{t("severityRewards")}</h4>
Expand Down
Loading