diff --git a/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/components/ReservedTokensSubPanel.tsx b/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/components/ReservedTokensSubPanel.tsx index c07d576d2c..dd52a9614f 100644 --- a/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/components/ReservedTokensSubPanel.tsx +++ b/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/components/ReservedTokensSubPanel.tsx @@ -54,7 +54,9 @@ export const ReservedTokensSubPanel = ({ items: kebabMenuItems, }} > - {reservedList?.length ? ( + {reservedTokens || + reservedRate || + (reservedList && reservedList.length > 1) ? ( <>
{reservedList diff --git a/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/hooks/useReservedTokensSubPanel.test.ts b/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/hooks/useReservedTokensSubPanel.test.ts index 4f77eef565..f9b1f30387 100644 --- a/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/hooks/useReservedTokensSubPanel.test.ts +++ b/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/hooks/useReservedTokensSubPanel.test.ts @@ -18,6 +18,7 @@ describe('useReservedTokensSubPanel', () => { projectId: 1, } const DefaultProjectContext = { + projectOwnerAddress: '0x0000000000000000000000000000000000000000', fundingCycleMetadata: { reservedRate: 10000, }, @@ -52,6 +53,11 @@ describe('useReservedTokensSubPanel', () => { it('returns sorted reservedList when reservedTokensSplits is defined', () => { const { result } = renderHook(useReservedTokensSubPanel) expect(result.current.reservedList).toEqual([ + { + projectId: 1, + address: '0x0000000000000000000000000000000000000000', + percent: '97%', + }, { projectId: undefined, address: '0x456', diff --git a/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/hooks/useReservedTokensSubPanel.ts b/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/hooks/useReservedTokensSubPanel.ts index 0c5b71dd08..4ddb02c602 100644 --- a/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/hooks/useReservedTokensSubPanel.ts +++ b/src/components/v2v3/V2V3Project/ProjectDashboard/components/TokensPanel/hooks/useReservedTokensSubPanel.ts @@ -2,6 +2,7 @@ import { useProjectContext, useProjectMetadata, } from 'components/v2v3/V2V3Project/ProjectDashboard/hooks' +import { ONE_BILLION } from 'constants/numbers' import { BigNumber } from 'ethers' import { useProjectReservedTokens } from 'hooks/v2v3/contractReader/ProjectReservedTokens' import { useMemo } from 'react' @@ -10,9 +11,12 @@ import { formatAmount } from 'utils/format/formatAmount' import { fromWad } from 'utils/format/formatNumber' import { formatReservedRate, formatSplitPercent } from 'utils/v2v3/math' +const ONE_BILLION_BIG = BigNumber.from(ONE_BILLION) + export const useReservedTokensSubPanel = () => { const { projectId } = useProjectMetadata() - const { fundingCycleMetadata, reservedTokensSplits } = useProjectContext() + const { fundingCycleMetadata, reservedTokensSplits, projectOwnerAddress } = + useProjectContext() const reservedRateWad = fundingCycleMetadata?.reservedRate const { data: reservedTokensWad } = useProjectReservedTokens({ @@ -21,20 +25,60 @@ export const useReservedTokensSubPanel = () => { }) const reservedList = useMemo(() => { - if (!reservedTokensSplits) return undefined - return reservedTokensSplits + if (!projectOwnerAddress || !projectId || !reservedTokensSplits) return + // If there aren't explicitly defined splits, all reserved tokens go to this project. + if (reservedTokensSplits?.length === 0) + return [ + { + projectId, + address: projectOwnerAddress!, + percent: `${formatSplitPercent(ONE_BILLION_BIG)}%`, + }, + ] + + // If the splits don't add up to 100%, remaining tokens go to this project. + let splitsPercentTotal = BigNumber.from(0) + const processedSplits = reservedTokensSplits .sort((a, b) => Number(b.percent) - Number(a.percent)) .map(split => { assert(split.beneficiary, 'Beneficiary must be defined') + const splitPercent = BigNumber.from(split.percent) + splitsPercentTotal = splitsPercentTotal.add(splitPercent) + return { projectId: split.projectId ? BigNumber.from(split.projectId).toNumber() : undefined, address: split.beneficiary!, - percent: `${formatSplitPercent(BigNumber.from(split.percent))}%`, + percent: `${formatSplitPercent(splitPercent)}%`, } }) - }, [reservedTokensSplits]) + + const remainingPercentage = ONE_BILLION_BIG.sub(splitsPercentTotal) + + // Check if this project is already one of the splits. + if (!remainingPercentage.isZero()) { + const projectSplitIndex = processedSplits.findIndex( + v => v.projectId === projectId, + ) + if (projectSplitIndex != -1) + // If it is, increase its split percentage to bring the total to 100%. + processedSplits[projectSplitIndex].percent = `${formatSplitPercent( + remainingPercentage.add( + reservedTokensSplits[projectSplitIndex].percent, + ), + )}%` + // If it isn't, add a split at the beginning which brings the total percentage to 100%. + else + processedSplits.unshift({ + projectId, + address: projectOwnerAddress!, + percent: `${formatSplitPercent(remainingPercentage)}%`, + }) + } + + return processedSplits + }, [reservedTokensSplits, projectOwnerAddress, projectId]) const reservedRate = useMemo(() => { if (!reservedRateWad) return undefined