Skip to content

Commit

Permalink
Migrate LosingRewardsBanner to voting power economics (#6238)
Browse files Browse the repository at this point in the history
# Motivation

Currently, the voting power parameters are hardcoded as half a year and
one month. However, actual values are already being retrieved from the
API (they are the same for now but may be updated in the future). The
general idea is that if the parameters are unavailable, we consider the
neuron active.

In this PR, we migrate `LosingRewardsBanner` from constants to the
voting power economics store.

# Changes

Switch from constant based to VP economics stores and utilities.
Do not show the component without voting power economics available (it
is loaded on dapp initialisation).

# Tests

- Updated.

# Todos

- [ ] Add entry to changelog (if necessary).
Not necessary.
  • Loading branch information
mstrasinskis authored Jan 23, 2025
1 parent 782f78c commit 9c39101
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 14 deletions.
45 changes: 31 additions & 14 deletions frontend/src/lib/components/neurons/LosingRewardsBanner.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,61 @@
import Banner from "$lib/components/ui/Banner.svelte";
import BannerIcon from "$lib/components/ui/BannerIcon.svelte";
import {
isNeuronLosingRewards,
secondsUntilLosingRewards,
isNeuronLosingRewardsVPE,
secondsUntilLosingRewardsVPE,
} from "$lib/utils/neuron.utils";
import { soonLosingRewardNeuronsStore } from "$lib/derived/neurons.derived";
import { replacePlaceholders } from "$lib/utils/i18n.utils";
import { nonNullish, secondsToDuration } from "@dfinity/utils";
import type { NeuronInfo } from "@dfinity/nns";
import { START_REDUCING_VOTING_POWER_AFTER_SECONDS } from "$lib/constants/neurons.constants";
import { secondsToDissolveDelayDuration } from "$lib/utils/date.utils";
import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte";
import LosingRewardNeuronsModal from "$lib/modals/neurons/LosingRewardNeuronsModal.svelte";
import { startReducingVotingPowerAfterSecondsStore } from "$lib/derived/network-economics.derived";
// The neurons in the store are sorted by the time they will lose rewards.
let mostInactiveNeuron: NeuronInfo | undefined;
$: mostInactiveNeuron = $soonLosingRewardNeuronsStore[0];
const getTitle = (neuron: NeuronInfo) =>
isNeuronLosingRewards(neuron)
const getTitle = ({
neuron,
startReducingVotingPowerAfterSeconds,
}: {
neuron: NeuronInfo;
startReducingVotingPowerAfterSeconds: bigint;
}) =>
isNeuronLosingRewardsVPE({ neuron, startReducingVotingPowerAfterSeconds })
? $i18n.losing_rewards_banner.rewards_missing_title
: replacePlaceholders($i18n.losing_rewards_banner.days_left_title, {
$timeLeft: secondsToDuration({
seconds: BigInt(secondsUntilLosingRewards(neuron)),
seconds: BigInt(
secondsUntilLosingRewardsVPE({
neuron,
startReducingVotingPowerAfterSeconds,
})
),
i18n: $i18n.time,
}),
});
const text = replacePlaceholders($i18n.losing_rewards.description, {
// TODO(mstr): Rename to secondsToRoundedDuration
$period: secondsToDissolveDelayDuration(
BigInt(START_REDUCING_VOTING_POWER_AFTER_SECONDS)
),
});
let isModalVisible = false;
</script>

<TestIdWrapper testId="losing-rewards-banner-component">
{#if nonNullish(mostInactiveNeuron)}
<Banner title={getTitle(mostInactiveNeuron)} {text}>
{#if nonNullish(mostInactiveNeuron) && nonNullish($startReducingVotingPowerAfterSecondsStore)}
<Banner
title={getTitle({
neuron: mostInactiveNeuron,
startReducingVotingPowerAfterSeconds:
$startReducingVotingPowerAfterSecondsStore,
})}
text={replacePlaceholders($i18n.losing_rewards.description, {
// TODO(mstr): Rename to secondsToRoundedDuration
$period: secondsToDissolveDelayDuration(
$startReducingVotingPowerAfterSecondsStore
),
})}
>
<BannerIcon slot="icon" status="error">
<IconInfo />
</BannerIcon>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import * as governanceApi from "$lib/api/governance.api";
import LosingRewardsBanner from "$lib/components/neurons/LosingRewardsBanner.svelte";
import { SECONDS_IN_DAY, SECONDS_IN_HALF_YEAR } from "$lib/constants/constants";
import { networkEconomicsStore } from "$lib/stores/network-economics.store";
import { neuronsStore } from "$lib/stores/neurons.store";
import { nowInSeconds } from "$lib/utils/date.utils";
import { mockIdentity, resetIdentity } from "$tests/mocks/auth.store.mock";
import { mockNetworkEconomics } from "$tests/mocks/network-economics.mock";
import { mockFullNeuron, mockNeuron } from "$tests/mocks/neurons.mock";
import { LosingRewardsBannerPo } from "$tests/page-objects/LosingRewardsBanner.page-object";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
Expand Down Expand Up @@ -70,6 +72,11 @@ describe("LosingRewardsBanner", () => {
vi.spyOn(governanceApi, "queryKnownNeurons").mockResolvedValue([]);
vi.spyOn(governanceApi, "queryNeurons").mockResolvedValue(refreshedNeurons);
vi.spyOn(governanceApi, "refreshVotingPower").mockResolvedValue();

networkEconomicsStore.setParameters({
parameters: mockNetworkEconomics,
certified: true,
});
});

it("should not display banner when all neurons are active", async () => {
Expand All @@ -81,6 +88,16 @@ describe("LosingRewardsBanner", () => {
expect(await po.isVisible()).toBe(false);
});

it("should not display banner w/o voting power economics", async () => {
networkEconomicsStore.reset();
neuronsStore.setNeurons({
neurons: [losingRewardsNeuron],
certified: true,
});
const po = await renderComponent();
expect(await po.isVisible()).toBe(false);
});

it("should display banner when soon inactive neuron available", async () => {
neuronsStore.setNeurons({
neurons: [losingRewardsNeuron],
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/tests/lib/pages/NnsNeurons.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import NnsNeurons from "$lib/pages/NnsNeurons.svelte";
import * as authServices from "$lib/services/auth.services";
import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store";
import { icpSwapTickersStore } from "$lib/stores/icp-swap.store";
import { networkEconomicsStore } from "$lib/stores/network-economics.store";
import { nowInSeconds } from "$lib/utils/date.utils";
import { mockIdentity, resetIdentity } from "$tests/mocks/auth.store.mock";
import { mockIcpSwapTicker } from "$tests/mocks/icp-swap.mock";
import { mockNetworkEconomics } from "$tests/mocks/network-economics.mock";
import { mockFullNeuron, mockNeuron } from "$tests/mocks/neurons.mock";
import { NnsNeuronsPo } from "$tests/page-objects/NnsNeurons.page-object";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
Expand Down Expand Up @@ -194,6 +196,10 @@ describe("NnsNeurons", () => {
},
},
]);
networkEconomicsStore.setParameters({
parameters: mockNetworkEconomics,
certified: true,
});
});

it("should not display LosingRewardsBanner by default", async () => {
Expand Down
22 changes: 22 additions & 0 deletions frontend/src/tests/lib/routes/Staking.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AppPath } from "$lib/constants/routes.constants";
import { pageStore } from "$lib/derived/page.derived";
import Staking from "$lib/routes/Staking.svelte";
import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store";
import { networkEconomicsStore } from "$lib/stores/network-economics.store";
import { neuronsStore } from "$lib/stores/neurons.store";
import { snsNeuronsStore } from "$lib/stores/sns-neurons.store";
import { nowInSeconds } from "$lib/utils/date.utils";
Expand All @@ -19,6 +20,7 @@ import {
setNoIdentity,
} from "$tests/mocks/auth.store.mock";
import { mockAccountsStoreData } from "$tests/mocks/icp-accounts.store.mock";
import { mockNetworkEconomics } from "$tests/mocks/network-economics.mock";
import { mockFullNeuron, mockNeuron } from "$tests/mocks/neurons.mock";
import { mockSnsNeuron } from "$tests/mocks/sns-neurons.mock";
import { mockToken, principal } from "$tests/mocks/sns-projects.mock";
Expand Down Expand Up @@ -416,6 +418,11 @@ describe("Staking", () => {
],
certified: true,
});

networkEconomicsStore.setParameters({
parameters: mockNetworkEconomics,
certified: true,
});
});

it("should not display LosingRewardsBanner by default", async () => {
Expand All @@ -434,5 +441,20 @@ describe("Staking", () => {
expect(await po.getLosingRewardsBannerPo().isPresent()).toBe(true);
expect(await po.getLosingRewardsBannerPo().isVisible()).toBe(true);
});

it("should not display LosingRewardsBanner w/o voting power economics", async () => {
networkEconomicsStore.setParameters({
parameters: undefined,
certified: undefined,
});
overrideFeatureFlagsStore.setFlag(
"ENABLE_PERIODIC_FOLLOWING_CONFIRMATION",
true
);
const po = await renderComponent();

expect(await po.getLosingRewardsBannerPo().isPresent()).toBe(true);
expect(await po.getLosingRewardsBannerPo().isVisible()).toBe(false);
});
});
});

0 comments on commit 9c39101

Please sign in to comment.