diff --git a/frontend/src/lib/components/neuron-detail/NeuronSelectPercentage.svelte b/frontend/src/lib/components/neuron-detail/NeuronSelectPercentage.svelte index 8aad36b5299..6ebaebf3427 100644 --- a/frontend/src/lib/components/neuron-detail/NeuronSelectPercentage.svelte +++ b/frontend/src/lib/components/neuron-detail/NeuronSelectPercentage.svelte @@ -6,11 +6,14 @@ import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte"; import { formatMaturity } from "$lib/utils/neuron.utils"; import { replacePlaceholders } from "$lib/utils/i18n.utils"; + import { nonNullish } from "@dfinity/utils"; + import Tooltip from "../ui/Tooltip.svelte"; export let availableMaturityE8s: bigint; export let percentage: number; export let buttonText: string; export let disabled = false; + export let disabledText: string | undefined = undefined; let selectedMaturityE8s: bigint; $: selectedMaturityE8s = (availableMaturityE8s * BigInt(percentage)) / 100n; @@ -59,14 +62,27 @@ - + {#if nonNullish(disabledText)} + + + + {:else} + + {/if} diff --git a/frontend/src/lib/modals/neurons/DisburseMaturityModal.svelte b/frontend/src/lib/modals/neurons/DisburseMaturityModal.svelte index 745e2088ff2..8311767ccb7 100644 --- a/frontend/src/lib/modals/neurons/DisburseMaturityModal.svelte +++ b/frontend/src/lib/modals/neurons/DisburseMaturityModal.svelte @@ -17,6 +17,9 @@ export let availableMaturityE8s: bigint; export let tokenSymbol: string; + // 99% of users will disburse more than the transaction fee. + // We don't want a possible error fetching the fee to disrupt the whole flow. + export let transactionFeeE8s = 0n; const steps: WizardSteps = [ { @@ -33,6 +36,22 @@ let modal: WizardModal; let percentageToDisburse = 0; + let selectedMaturityE8s: bigint; + $: selectedMaturityE8s = + (availableMaturityE8s * BigInt(percentageToDisburse)) / 100n; + + let disableDisburse = false; + $: disableDisburse = selectedMaturityE8s < transactionFeeE8s; + + // Show the text only if the selected percentage is greater than 0. + let disabledText: string | undefined = undefined; + $: disabledText = + disableDisburse && percentageToDisburse > 0 + ? replacePlaceholders( + $i18n.neuron_detail.disburse_maturity_disabled_tooltip, + { $fee: formatToken({ value: transactionFeeE8s }) } + ) + : undefined; const dispatcher = createEventDispatcher(); const disburseNeuronMaturity = () => @@ -74,7 +93,8 @@ on:nnsSelectPercentage={goToConfirm} on:nnsCancel={close} bind:percentage={percentageToDisburse} - disabled={percentageToDisburse === 0} + disabled={disableDisburse} + {disabledText} >
diff --git a/frontend/src/lib/modals/sns/neurons/SnsDisburseMaturityModal.svelte b/frontend/src/lib/modals/sns/neurons/SnsDisburseMaturityModal.svelte index 5f6bfe3b874..6c3041fdbd7 100644 --- a/frontend/src/lib/modals/sns/neurons/SnsDisburseMaturityModal.svelte +++ b/frontend/src/lib/modals/sns/neurons/SnsDisburseMaturityModal.svelte @@ -10,7 +10,8 @@ import { snsProjectMainAccountStore } from "$lib/derived/sns/sns-project-accounts.derived"; import { shortenWithMiddleEllipsis } from "$lib/utils/format.utils"; import { tokensStore } from "$lib/stores/tokens.store"; - import type { Token } from "@dfinity/utils"; + import { selectedUniverseIdStore } from "$lib/derived/selected-universe.derived"; + import type { IcrcTokenMetadata } from "$lib/types/icrc"; export let neuron: SnsNeuron; export let neuronId: SnsNeuronId; @@ -25,8 +26,8 @@ $snsProjectMainAccountStore?.identifier ?? "" ); - let token: Token | undefined; - $: token = $tokensStore[rootCanisterId.toText()]?.token; + let token: IcrcTokenMetadata | undefined; + $: token = $tokensStore[$selectedUniverseIdStore.toText()]?.token; const dispatcher = createEventDispatcher(); const close = () => dispatcher("nnsClose"); @@ -57,6 +58,7 @@ { expect(await po.isNextButtonDisabled()).toBe(false); }); + it("should disable next button if amount of maturity is less than transaction fee", async () => { + const fee = 100_000_000n; + const neuron = createMockSnsNeuron({ + id: [1], + maturity: fee * 2n, + }); + tokensStore.setToken({ + canisterId: rootCanisterId, + token: { + fee, + ...mockSnsToken, + }, + }); + // Maturity is 2x the fee, so 10% of maturity is not enough to cover the fee + const percentage = 10; + const po = await renderSnsDisburseMaturityModal(neuron); + await po.setPercentage(percentage); + expect(await po.isNextButtonDisabled()).toBe(false); + }); + it("should display selected percentage and total maturity", async () => { const neuron = createMockSnsNeuron({ id: [1],