All files / app/pages/stacking/direct-stacking/components choose-direct-stacking-amount.tsx

0% Statements 0/33
0% Branches 0/14
0% Functions 0/3
0% Lines 0/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149                                                                                                                                                                                                                                                                                                         
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import {
  StackingStep as Step,
  StackingStepDescription as Description,
} from '../../components/stacking-form-step';
import { StackingStepBaseProps } from '../../utils/abstract-stacking-step';
import { calculateRewardSlots, calculateStackingBuffer } from '../../utils/calc-stacking-buffer';
import { ErrorLabel } from '@components/error-label';
import { ErrorText } from '@components/error-text';
import { ExternalLink } from '@components/external-link';
import { pseudoBorderLeft } from '@components/styles/pseudo-border-left';
import {
  STACKING_CONTRACT_CALL_TX_BYTES,
  STACKING_LEARN_MORE_URL,
  STACKING_MINIMIUM_FOR_NEXT_CYCLE_URL,
} from '@constants/index';
import { useBalance } from '@hooks/use-balance';
import { Box, Button, color, Input, Stack, Text } from '@stacks/ui';
import { selectPoxInfo } from '@store/stacking';
import { microStxToStx, stxToMicroStx, toHumanReadableStx } from '@utils/unit-convert';
import { BigNumber } from 'bignumber.js';
import { useField } from 'formik';
import React, { FC, useCallback } from 'react';
import { useSelector } from 'react-redux';
 
interface ChooseAmountFieldProps extends StackingStepBaseProps {
  minimumAmountToStack: number;
}
 
const BigNumberFloorRound = BigNumber.clone({ ROUNDING_MODE: BigNumber.ROUND_FLOOR });
 
export const ChooseDirectStackingAmountField: FC<ChooseAmountFieldProps> = props => {
  const { minimumAmountToStack } = props;
 
  const [field, meta, helpers] = useField('amount');
 
  const { availableBalance } = useBalance();
  const poxInfo = useSelector(selectPoxInfo);
 
  const ustxAmount = stxToMicroStx(field.value || 0);
 
  const showStackingWarningCard = ustxAmount.isGreaterThanOrEqualTo(minimumAmountToStack);
 
  const setMax = useCallback(() => {
    const updatedAmount = new BigNumberFloorRound(
      microStxToStx(availableBalance.minus(STACKING_CONTRACT_CALL_TX_BYTES).toString())
    ).decimalPlaces(0);
    void helpers.setValue(updatedAmount.toString());
  }, [availableBalance, helpers]);
 
  Iif (poxInfo === null) return null;
 
  const numberOfRewardSlots = calculateRewardSlots(
    ustxAmount,
    new BigNumber(poxInfo.min_amount_ustx)
  ).integerValue();
 
  const floorRoundedStxBuffer = calculateStackingBuffer(
    ustxAmount,
    new BigNumber(poxInfo.min_amount_ustx)
  );
 
  return (
    <Step title="Choose amount">
      <Description>
        <Stack alignItems="flex-start" spacing="base">
          <Text>
            You&apos;ll be eligible for one reward slot for every multiple of the minimum you stack.
          </Text>
          <Text>
            The estimated minimum per slot can change by multiples of 10,000 every cycle, so you may
            want to add a buffer to increase your chance of keeping the same number of slots.
          </Text>
          <ExternalLink href={STACKING_LEARN_MORE_URL}>
            Learn how to choose the right amount
          </ExternalLink>
          <ExternalLink href={STACKING_MINIMIUM_FOR_NEXT_CYCLE_URL}>
            View the minimum for next cycle
          </ExternalLink>
        </Stack>
      </Description>
 
      <Box position="relative" maxWidth="400px">
        <Input id="stxAmount" placeholder="Amount of STX to Stack" mt="loose" {...field} />
        {meta.touched && meta.error && (
          <ErrorLabel>
            <ErrorText>{meta.error}</ErrorText>
          </ErrorLabel>
        )}
        <Button
          type="button"
          mode="tertiary"
          size="sm"
          height="28px"
          right="12px"
          top="10px"
          style={{ position: 'absolute' }}
          width="80px"
          onClick={setMax}
        >
          Stack max
        </Button>
      </Box>
      {showStackingWarningCard && (
        <>
          <Stack textStyle="body.small" color={color('text-caption')} spacing="base" mt="base">
            <Text>
              This entered amount would get you {numberOfRewardSlots.toString()} reward slot
              {numberOfRewardSlots.toNumber() === 1 ? '' : 's'} with a{' '}
              {toHumanReadableStx(floorRoundedStxBuffer || 0)} buffer at the current minimum.
              However, that minimum is subject to change and there is no guarantee you will get any
              reward slots.
            </Text>
            <Text>
              You <strong>will not</strong> be able to add more STX for locking from this address
              until all locked STX unlock at the end of the duration set below.
            </Text>
          </Stack>
          {floorRoundedStxBuffer.isEqualTo(0) && (
            <Box
              textStyle="body.small"
              color={color('text-body')}
              border="1px solid"
              p="loose"
              mt="base"
              borderRadius="6px"
              borderColor={color('border')}
              {...pseudoBorderLeft('feedback-alert')}
            >
              Add a buffer for a higher chance (though no guarantee) of keeping the same number of
              reward slots should the minimum increase. If you can&apos;t add a buffer, consider
              Stacking in a pool instead.
              <Button
                variant="link"
                type="button"
                display="block"
                mt="tight"
                onClick={() => helpers.setValue(new BigNumber(field.value).plus(10000).toString())}
              >
                Add 10,000 STX buffer
              </Button>
            </Box>
          )}
        </>
      )}
    </Step>
  );
};