Skip to content

Commit

Permalink
Feat: Add amount of maturity to NeuronSelectPercentage (#3314)
Browse files Browse the repository at this point in the history
# Motivation

Improving the disburse maturity flow.

This PR is one of the few I'll do to split #3284 into smaller PRs.

In this PR, we add the amount of maturity in the component where a
percentage of maturity is selected.

# Changes

* New sns neuron util `maturityPercentageToE8s`.
* Use new sns neuron util in NeuronSelectPercantage to show the amount
of maturity related to the percentage.

# Tests

* Test new util.
* Test that the amount of maturity is visible in the
DisburseMaturityModal.

# Todos

- [x] Add entry to changelog (if necessary).
  • Loading branch information
lmuntaner authored Sep 13, 2023
1 parent a1e74ad commit 3eb8d98
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 27 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG-Nns-Dapp.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The NNS Dapp is released through proposals in the Network Nervous System. Theref

#### Added

* Add the amount of maturity related to a selected percentage.

#### Changed

* Show the token selector also when not signed in.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@
import { InputRange, KeyValuePair } from "@dfinity/gix-components";
import { createEventDispatcher } from "svelte";
import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte";
import { maturityPercentageToE8s } from "$lib/utils/neuron.utils";
import { formatMaturity } from "$lib/utils/neuron.utils";
import { replacePlaceholders } from "$lib/utils/i18n.utils";
export let formattedMaturity: string;
export let percentage: number;
export let buttonText: string;
export let disabled = false;
let maturityE8s: bigint;
$: maturityE8s = maturityPercentageToE8s({
percentage,
total: Number(formattedMaturity),
});
const dispatcher = createEventDispatcher();
const selectPercentage = () => dispatcher("nnsSelectPercentage");
</script>
Expand All @@ -34,10 +43,17 @@
bind:value={percentage}
/>
<h5>
{formatPercentage(percentage / 100, {
minFraction: 0,
maxFraction: 0,
})}
<span class="description" data-tid="amount-maturity"
>{replacePlaceholders($i18n.neuron_detail.amount_maturity, {
$amount: formatMaturity(maturityE8s),
})}</span
>
<span data-tid="percentage-to-disburse"
>{formatPercentage(percentage / 100, {
minFraction: 0,
maxFraction: 0,
})}</span
>
</h5>
</div>

Expand All @@ -58,15 +74,15 @@

<style lang="scss">
.label {
padding-top: var(--padding-3x);
margin: var(--padding-1_5x) 0 var(--padding);
}
.select-container {
width: 100%;
h5 {
margin-top: var(--padding);
text-align: center;
text-align: right;
}
}
</style>
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@
"advanced_settings_title": "Advanced details & settings",
"neuron_account": "Neuron Account",
"dissolve_date": "Dissolve Date",
"amount_maturity": "$amount maturity",
"created": "Date created"
},
"sns_launchpad": {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/types/i18n.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ interface I18nNeuron_detail {
advanced_settings_title: string;
neuron_account: string;
dissolve_date: string;
amount_maturity: string;
created: string;
}

Expand Down
15 changes: 14 additions & 1 deletion frontend/src/lib/utils/neuron.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import { nowInSeconds } from "./date.utils";
import { formatNumber } from "./format.utils";
import { getVotingBallot, getVotingPower } from "./proposals.utils";
import { toNnsVote } from "./sns-proposals.utils";
import { formatToken } from "./token.utils";
import { formatToken, numberToE8s } from "./token.utils";
import { isDefined } from "./utils";

export type StateInfo = {
Expand Down Expand Up @@ -954,3 +954,16 @@ export const maturityLastDistribution = ({

export const neuronDashboardUrl = ({ neuronId }: NeuronInfo): string =>
`https://dashboard.internetcomputer.org/neuron/${neuronId.toString()}`;

export const maturityPercentageToE8s = ({
total,
percentage,
}: {
total: number;
percentage: number;
}): bigint =>
numberToE8s(
// Use toFixed to avoid Token validation error "Number X has more than 8 decimals"
// due to `numberToE8s` validation of floating-point approximation issues of IEEE 754 (e.g. 0.1 + 0.2 = 0.30000000000000004)
Number(((percentage / 100) * total).toFixed(8))
);
46 changes: 26 additions & 20 deletions frontend/src/tests/lib/modals/sns/SnsDisburseMaturityModal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,35 @@ import SnsDisburseMaturityModal from "$lib/modals/sns/neurons/SnsDisburseMaturit
import { authStore } from "$lib/stores/auth.store";
import { mockIdentity, mockPrincipal } from "$tests/mocks/auth.store.mock";
import { renderModal } from "$tests/mocks/modal.mock";
import { mockSnsNeuron } from "$tests/mocks/sns-neurons.mock";
import {
createMockSnsNeuron,
mockSnsNeuron,
} from "$tests/mocks/sns-neurons.mock";
import { DisburseMaturityModalPo } from "$tests/page-objects/DisburseMaturityModal.page-object";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
import type { SnsNeuron } from "@dfinity/sns";
import { waitFor } from "@testing-library/svelte";

jest.mock("$lib/api/sns-governance.api");

describe("SnsDisburseMaturityModal", () => {
const reloadNeuron = jest.fn();

const props = {
neuronId: mockSnsNeuron.id,
neuron: mockSnsNeuron,
rootCanisterId: mockPrincipal,
reloadNeuron,
const renderSnsDisburseMaturityModal = async (
neuron: SnsNeuron = mockSnsNeuron
): Promise<DisburseMaturityModalPo> => {
const { container } = await renderModal({
component: SnsDisburseMaturityModal,
props: {
neuronId: neuron.id,
neuron,
rootCanisterId: mockPrincipal,
reloadNeuron,
},
});
return DisburseMaturityModalPo.under(new JestPageObjectElement(container));
};

const renderSnsDisburseMaturityModal =
async (): Promise<DisburseMaturityModalPo> => {
const { container } = await renderModal({
component: SnsDisburseMaturityModal,
props,
});
return DisburseMaturityModalPo.under(
new JestPageObjectElement(container)
);
};

beforeEach(() => {
authStore.setForTesting(mockIdentity);
});
Expand All @@ -51,11 +52,16 @@ describe("SnsDisburseMaturityModal", () => {
expect(await po.isNextButtonDisabled()).toBe(false);
});

it("should display selected percentage", async () => {
const po = await renderSnsDisburseMaturityModal();
it("should display selected percentage and total maturity", async () => {
const neuron = createMockSnsNeuron({
id: [1],
maturity: 1_000_000_000n,
});
const po = await renderSnsDisburseMaturityModal(neuron);
await po.setPercentage(13);
await po.clickNextButton();
expect(await po.getAmountMaturityToDisburse()).toBe("1.30 maturity");

await po.clickNextButton();
expect(await po.getText()).toContain(`13%`);
});

Expand Down
21 changes: 21 additions & 0 deletions frontend/src/tests/lib/utils/neuron.utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
mapMergeableNeurons,
mapNeuronIds,
maturityLastDistribution,
maturityPercentageToE8s,
minNeuronSplittable,
neuronAge,
neuronCanBeSplit,
Expand Down Expand Up @@ -2421,4 +2422,24 @@ describe("neuron-utils", () => {
).toBe(false);
});
});

describe("maturityPercentageToE8s", () => {
it("calculates percents ", () => {
expect(
maturityPercentageToE8s({
total: 100,
percentage: 50,
})
).toEqual(5_000_000_000n);
});

it("handles more than 8 decimals results", () => {
expect(
maturityPercentageToE8s({
total: 1.00001,
percentage: 1,
})
).toEqual(1_000_010n);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ export class DisburseMaturityModalPo extends BasePageObject {
setPercentage(percentage: number): Promise<void> {
return this.getNeuronSelectPercentagePo().setPercentage(percentage);
}

getAmountMaturityToDisburse(): Promise<string> {
return this.getNeuronSelectPercentagePo().getAmountMaturity();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ export class NeuronSelectPercentagePo extends BasePageObject {
setPercentage(percentage: number): Promise<void> {
return this.getInputRangePo().setValue(percentage);
}

getAmountMaturity(): Promise<string> {
return this.getText("amount-maturity");
}
}

0 comments on commit 3eb8d98

Please sign in to comment.