diff --git a/frontend/src/lib/utils/neuron.utils.ts b/frontend/src/lib/utils/neuron.utils.ts index 080ac66b2db..bff24ba1e24 100644 --- a/frontend/src/lib/utils/neuron.utils.ts +++ b/frontend/src/lib/utils/neuron.utils.ts @@ -1186,16 +1186,19 @@ const getVotingPowerRefreshedTimestampSeconds = ({ // to avoid unnecessary notifications. fullNeuron?.votingPowerRefreshedTimestampSeconds ?? BigInt(nowInSeconds()); +export const secondsUntilLosingRewards = (neuron: NeuronInfo): number => { + const rewardLossStart = + Number(getVotingPowerRefreshedTimestampSeconds(neuron)) + + START_REDUCING_VOTING_POWER_AFTER_SECONDS; + return rewardLossStart - nowInSeconds(); +}; + export const isNeuronLosingRewards = (neuron: NeuronInfo): boolean => - nowInSeconds() >= - getVotingPowerRefreshedTimestampSeconds(neuron) + - BigInt(START_REDUCING_VOTING_POWER_AFTER_SECONDS); + secondsUntilLosingRewards(neuron) <= 0; // e.g. "Neuron will start losing rewards in 30 days" export const shouldDisplayRewardLossNotification = ( neuron: NeuronInfo ): boolean => - nowInSeconds() >= - getVotingPowerRefreshedTimestampSeconds(neuron) + - BigInt(START_REDUCING_VOTING_POWER_AFTER_SECONDS) - - BigInt(daysToSeconds(NOTIFICATION_PERIOD_BEFORE_REWARD_LOSS_STARTS_DAYS)); + secondsUntilLosingRewards(neuron) <= + daysToSeconds(NOTIFICATION_PERIOD_BEFORE_REWARD_LOSS_STARTS_DAYS); diff --git a/frontend/src/tests/lib/utils/neuron.utils.spec.ts b/frontend/src/tests/lib/utils/neuron.utils.spec.ts index 27a0423400f..88b85af780c 100644 --- a/frontend/src/tests/lib/utils/neuron.utils.spec.ts +++ b/frontend/src/tests/lib/utils/neuron.utils.spec.ts @@ -65,6 +65,7 @@ import { neuronStakedMaturity, neuronVotingPower, neuronsVotingPower, + secondsUntilLosingRewards, shouldDisplayRewardLossNotification, sortNeuronsByStake, sortNeuronsByVotingPowerRefreshedTimeout, @@ -3294,6 +3295,34 @@ describe("neuron-utils", () => { const losingRewardsPeriod = SECONDS_IN_HALF_YEAR; const notificationPeriod = 30 * SECONDS_IN_DAY; + describe("secondsUntilLosingRewards", () => { + it("should return future date when no fullNeuron", () => { + expect( + secondsUntilLosingRewards({ + ...mockNeuron, + fullNeuron: undefined, + }) + ).toEqual(SECONDS_IN_HALF_YEAR); + }); + + it("should return seconds until losing rewards", () => { + expect( + secondsUntilLosingRewards( + neuronWithRefreshedTimestamp({ + votingPowerRefreshedTimestampAgeSecs: 0, + }) + ) + ).toBe(SECONDS_IN_HALF_YEAR); + expect( + secondsUntilLosingRewards( + neuronWithRefreshedTimestamp({ + votingPowerRefreshedTimestampAgeSecs: losingRewardsPeriod, + }) + ) + ).toBe(0); + }); + }); + describe("isNeuronLosingRewards", () => { it("should return false by default", () => { expect(