From 253a302df6f73d11980db2ffd94705a6ebab0166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lloren=C3=A7=20Muntaner?= Date: Thu, 14 Sep 2023 16:08:22 +0200 Subject: [PATCH] GIX-1889: Fix blank modal disburse maturity (#3317) # Motivation There was a bug when NeuronSelectPercentage was used for maturity above 1000. That's because now we started calculating the maturity of the percentage. Yet, the maturity was passed as a string and then converted to a number. If the number was larger than 1000, then the string couldn't be converted successfully to a number. The solution was to expect a number instead of a string. # Changes * Change `formttedMaturity` in NeuronSelectPercentage for `availableMaturityE8s`. Change accordingly. * Change where the NeuronSelectPercentage was used to pass the maturity as e8s instead of as a string. * Remove unnecessary util `maturityPercentageToE8s`. Now it's a simple multiplication and division. No need to use an util for that. There is no logic to reuse. # Tests * I added a test that fails in `main` but succeeds in this PR. # Todos - [ ] Add entry to changelog (if necessary). --- .../NeuronSelectPercentage.svelte | 14 ++++------- .../neurons/DisburseMaturityModal.svelte | 24 ++++++++----------- .../neurons/NnsStakeMaturityModal.svelte | 2 +- .../modals/neurons/SpawnNeuronModal.svelte | 3 +-- .../modals/neurons/StakeMaturityModal.svelte | 4 ++-- .../neurons/SnsDisburseMaturityModal.svelte | 2 +- .../sns/neurons/SnsStakeMaturityModal.svelte | 2 +- frontend/src/lib/utils/neuron.utils.ts | 15 +----------- .../sns/SnsDisburseMaturityModal.spec.ts | 19 ++++++++++++--- .../src/tests/lib/utils/neuron.utils.spec.ts | 21 ---------------- 10 files changed, 38 insertions(+), 68 deletions(-) diff --git a/frontend/src/lib/components/neuron-detail/NeuronSelectPercentage.svelte b/frontend/src/lib/components/neuron-detail/NeuronSelectPercentage.svelte index c2cec12151b..8aad36b5299 100644 --- a/frontend/src/lib/components/neuron-detail/NeuronSelectPercentage.svelte +++ b/frontend/src/lib/components/neuron-detail/NeuronSelectPercentage.svelte @@ -4,20 +4,16 @@ 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 availableMaturityE8s: bigint; export let percentage: number; export let buttonText: string; export let disabled = false; - let maturityE8s: bigint; - $: maturityE8s = maturityPercentageToE8s({ - percentage, - total: Number(formattedMaturity), - }); + let selectedMaturityE8s: bigint; + $: selectedMaturityE8s = (availableMaturityE8s * BigInt(percentage)) / 100n; const dispatcher = createEventDispatcher(); const selectPercentage = () => dispatcher("nnsSelectPercentage"); @@ -29,7 +25,7 @@ >{$i18n.neuron_detail.available_maturity} {formattedMaturity}{formatMaturity(availableMaturityE8s)} @@ -47,7 +43,7 @@
{replacePlaceholders($i18n.neuron_detail.amount_maturity, { - $amount: formatMaturity(maturityE8s), + $amount: formatMaturity(selectedMaturityE8s), })} modal.next(); - let maturityToDisburse = 0n; - $: maturityToDisburse = maturityPercentageToE8s({ - total: Number(formattedMaturity), - percentage: percentageToDisburse, - }); + let maturityToDisburseE8s: bigint; + $: maturityToDisburseE8s = + (availableMaturityE8s * BigInt(percentageToDisburse)) / 100n; + // +/- 5% let predictedMinimumTokens: string; $: predictedMinimumTokens = formatToken({ - value: BigInt(Number(maturityToDisburse) * 0.95), + value: BigInt(Math.round(Number(maturityToDisburseE8s) * 0.95)), }); let predictedMaximumTokens: string; $: predictedMaximumTokens = formatToken({ - value: BigInt(Number(maturityToDisburse) * 1.05), + value: BigInt(Math.round(Number(maturityToDisburseE8s) * 1.05)), }); @@ -73,7 +69,7 @@ {#if currentStep?.name === "SelectPercentage"} {$i18n.neuron_detail.disburse_maturity_confirmation_amount} {formatMaturity(maturityToDisburse)} + >{formatMaturity(maturityToDisburseE8s)} diff --git a/frontend/src/lib/modals/neurons/NnsStakeMaturityModal.svelte b/frontend/src/lib/modals/neurons/NnsStakeMaturityModal.svelte index 1f81438ff61..3691e91ea43 100644 --- a/frontend/src/lib/modals/neurons/NnsStakeMaturityModal.svelte +++ b/frontend/src/lib/modals/neurons/NnsStakeMaturityModal.svelte @@ -40,7 +40,7 @@ diff --git a/frontend/src/lib/modals/neurons/SpawnNeuronModal.svelte b/frontend/src/lib/modals/neurons/SpawnNeuronModal.svelte index 73374a366fd..47637da0397 100644 --- a/frontend/src/lib/modals/neurons/SpawnNeuronModal.svelte +++ b/frontend/src/lib/modals/neurons/SpawnNeuronModal.svelte @@ -13,7 +13,6 @@ import { spawnNeuron } from "$lib/services/neurons.services"; import { toastsShow } from "$lib/stores/toasts.store"; import { - formattedMaturity, isEnoughMaturityToSpawn, isNeuronControlledByHardwareWallet, } from "$lib/utils/neuron.utils"; @@ -98,7 +97,7 @@ > {#if currentStep?.name === "SelectPercentage"} diff --git a/frontend/src/lib/utils/neuron.utils.ts b/frontend/src/lib/utils/neuron.utils.ts index 620a62a74f4..1994116d1c8 100644 --- a/frontend/src/lib/utils/neuron.utils.ts +++ b/frontend/src/lib/utils/neuron.utils.ts @@ -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, numberToE8s } from "./token.utils"; +import { formatToken } from "./token.utils"; import { isDefined } from "./utils"; export type StateInfo = { @@ -954,16 +954,3 @@ 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)) - ); diff --git a/frontend/src/tests/lib/modals/sns/SnsDisburseMaturityModal.spec.ts b/frontend/src/tests/lib/modals/sns/SnsDisburseMaturityModal.spec.ts index 5793e389be2..ac13d17b8e1 100644 --- a/frontend/src/tests/lib/modals/sns/SnsDisburseMaturityModal.spec.ts +++ b/frontend/src/tests/lib/modals/sns/SnsDisburseMaturityModal.spec.ts @@ -37,6 +37,7 @@ describe("SnsDisburseMaturityModal", () => { }; beforeEach(() => { + jest.clearAllMocks(); authStore.setForTesting(mockIdentity); }); @@ -80,8 +81,8 @@ describe("SnsDisburseMaturityModal", () => { expect(await po.getConfirmDestination()).toBe("Main"); }); - it("should call disburse maturity api and reloadNeuron", async () => { - const po = await renderSnsDisburseMaturityModal(); + const disburse = async (neuron: SnsNeuron) => { + const po = await renderSnsDisburseMaturityModal(neuron); await po.setPercentage(50); await po.clickNextButton(); @@ -93,11 +94,23 @@ describe("SnsDisburseMaturityModal", () => { expect(disburseMaturity).toBeCalledTimes(1); expect(disburseMaturity).toBeCalledWith({ - neuronId: mockSnsNeuron.id, + neuronId: neuron.id, rootCanisterId: mockPrincipal, percentageToDisburse: 50, identity: mockIdentity, }); await waitFor(() => expect(reloadNeuron).toBeCalledTimes(1)); + }; + + it("should call disburse maturity api and reloadNeuron", async () => { + await disburse(mockSnsNeuron); + }); + + it("should disburse maturity when maturity is larger than 1,000", async () => { + const neuron1100maturity = createMockSnsNeuron({ + id: [1], + maturity: 110_000_000_000n, + }); + await disburse(neuron1100maturity); }); }); diff --git a/frontend/src/tests/lib/utils/neuron.utils.spec.ts b/frontend/src/tests/lib/utils/neuron.utils.spec.ts index a8ef7db7497..cd7488c3163 100644 --- a/frontend/src/tests/lib/utils/neuron.utils.spec.ts +++ b/frontend/src/tests/lib/utils/neuron.utils.spec.ts @@ -55,7 +55,6 @@ import { mapMergeableNeurons, mapNeuronIds, maturityLastDistribution, - maturityPercentageToE8s, minNeuronSplittable, neuronAge, neuronCanBeSplit, @@ -2422,24 +2421,4 @@ 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); - }); - }); });