Skip to content

Commit

Permalink
Merge pull request #114 from threshold-network/staking-cards-qa
Browse files Browse the repository at this point in the history
Staking Cards- bug fixes

This commit fixes reported bugs from the QA feedback.

What's changed:

- allow unstake if pre node is not configured- we should not block unstaking in 
stake card if pre node is not configured.
- reset the top-up/unstakeform in staking card after switching between 
stake/unstake option,
- fix a bug with unstaking flow. The dapp crashes after submitting unstake T 
form in a modal. The problem was the form validation was disabled due to the 
incorrect setting the default value for shouldValidateForm prop,
- get rid of the LOW PRE FUNDS completely- the message is superfluous since it 
doesn't need to do any more transactions.
  • Loading branch information
michalsmiarowski authored May 19, 2022
2 parents d3e0a5d + 7a51f35 commit 63ae1e9
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 50 deletions.
9 changes: 7 additions & 2 deletions src/components/Forms/TokenAmountForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC } from "react"
import { FC, Ref } from "react"
import { Icon, Box } from "@chakra-ui/react"
import { withFormik, FormikProps, FormikErrors } from "formik"
import ThresholdCircleBrand from "../../static/icons/ThresholdCircleBrand"
Expand All @@ -8,7 +8,7 @@ import { Form } from "./Form"
import { getErrorsObj, validateAmountInRange } from "../../utils/forms"
import { formatTokenAmount } from "../../utils/formatAmount"

type FormValues = {
export type FormValues = {
tokenAmount: string
}

Expand All @@ -24,6 +24,7 @@ type TokenAmountFormProps = {
shouldValidateForm?: boolean
shouldDisplayMaxAmountInLabel?: boolean
token?: { decimals: number; symbol: string }
innerRef?: Ref<FormikProps<FormValues>>
}

const TokenAmountFormBase: FC<
Expand Down Expand Up @@ -96,3 +97,7 @@ export const TokenAmountForm = withFormik<TokenAmountFormProps, FormValues>({
},
displayName: "TokenAmountForm",
})(TokenAmountFormBase)

TokenAmountForm.defaultProps = {
shouldValidateForm: true,
}
10 changes: 7 additions & 3 deletions src/components/NumberInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ReactNumberFormat from "react-number-format"
import { chakra, InputProps, useMultiStyleConfig } from "@chakra-ui/react"
import { FC } from "react"
import { FC, forwardRef } from "react"

const ChakraWrapper = chakra(ReactNumberFormat)

Expand All @@ -15,7 +15,10 @@ export type NumberInputProps = InputProps & {
decimalScale?: number
}

const NumberInput: FC<NumberInputProps> = (props) => {
const NumberInput: FC<NumberInputProps> = forwardRef<
HTMLInputElement,
NumberInputProps
>((props, ref) => {
const { field: css } = useMultiStyleConfig("Input", props)

const { decimalScale, isDisabled, ...restProps } = props
Expand All @@ -28,9 +31,10 @@ const NumberInput: FC<NumberInputProps> = (props) => {
decimalScale={decimalScale}
__css={css}
disabled={isDisabled}
getInputRef={ref}
{...restProps}
/>
)
}
})

export default NumberInput
24 changes: 21 additions & 3 deletions src/components/TokenBalanceInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, useRef } from "react"
import { FC, useEffect, useRef } from "react"
import {
Button,
Icon,
Expand Down Expand Up @@ -42,15 +42,31 @@ const TokenBalanceInput: FC<TokenBalanceInputProps> = ({
hasError = false,
...inputProps
}) => {
const valueRef = useRef<string>(amount as string)
const inputRef = useRef<HTMLInputElement>()
const valueRef = useRef<string | number | undefined>(amount)

useEffect(() => {
if (amount === "" && inputRef.current) {
const setValue = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value"
)?.set
setValue!.call(inputRef.current, "")
const event = new Event("change", { bubbles: true })
inputRef.current.dispatchEvent(event)
valueRef.current = undefined
}
})

const setToMax = () => {
_setAmount(formatUnits(max))
setAmount(valueRef.current)
}

const _setAmount = (value: string | number) => {
valueRef.current = parseUnits(value ? value.toString() : "0").toString()
valueRef.current = value
? parseUnits(value.toString()).toString()
: undefined
}

return (
Expand All @@ -61,6 +77,8 @@ const TokenBalanceInput: FC<TokenBalanceInputProps> = ({
<Icon boxSize="20px" as={icon} />
</InputLeftElement>
<NumberInput
// @ts-ignore
ref={inputRef}
placeholder="Enter an amount"
paddingLeft="2.5rem"
paddingRight="4.5rem"
Expand Down
1 change: 0 additions & 1 deletion src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * as vendingMachine from "./vendingMachine"
export * as stakingBonus from "./stakingBonus"
export * as pre from "./pre"
3 changes: 0 additions & 3 deletions src/constants/pre.ts

This file was deleted.

12 changes: 1 addition & 11 deletions src/hooks/useFetchPreConfigData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import { useCallback } from "react"
import { useMulticallContract, usePREContract } from "../web3/hooks"
import { decodeMulticallResult, getMulticallContractCall } from "../web3/utils"
import { PreConfigData } from "../types/staking"
import { useCheckEthBalanceForAccounts } from "./useCheckEthBalanceForAccounts"
import { isZeroAddress } from "ethereumjs-util"

export const useFetchPreConfigData = (): ((
stakingProviders: string[]
) => Promise<PreConfigData>) => {
const preContract = usePREContract()
const multicallContract = useMulticallContract()
const checkAccountsBalances = useCheckEthBalanceForAccounts()

return useCallback(
async (stakingProviders) => {
Expand Down Expand Up @@ -46,25 +43,18 @@ export const useFetchPreConfigData = (): ((
preConfigDataMulticalls
)

const accountsBalances = await checkAccountsBalances(
preConfigDataRaw.map((data) => data.operator)
)

return preConfigDataRaw.reduce(
(finalData: PreConfigData, _, idx): PreConfigData => {
finalData[stakingProviders[idx]] = {
operator: _.operator,
isOperatorConfirmed: _.operatorConfirmed,
operatorStartTimestamp: _.operatorStartTimestamp.toString(),
operatorEthBalance: isZeroAddress(_.operator)
? "0"
: accountsBalances[_.operator],
}
return finalData
},
{}
)
},
[preContract, multicallContract, checkAccountsBalances]
[preContract, multicallContract]
)
}
39 changes: 14 additions & 25 deletions src/pages/Staking/StakeCard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, ReactElement, Fragment } from "react"
import { FC, ReactElement, Fragment, useRef, useCallback } from "react"
import {
Flex,
Box,
Expand All @@ -12,6 +12,7 @@ import {
FlexProps,
} from "@chakra-ui/react"
import { InfoIcon } from "@chakra-ui/icons"
import { FormikProps } from "formik"
import { BigNumber } from "@ethersproject/bignumber"
import Card from "../../../components/Card"
import { Body2, Label3 } from "../../../components/Typography"
Expand All @@ -20,7 +21,7 @@ import TokenBalance from "../../../components/TokenBalance"
import InfoBox from "../../../components/InfoBox"
import BoxLabel from "../../../components/BoxLabel"
import { CopyAddressToClipboard } from "../../../components/CopyToClipboard"
import { TokenAmountForm } from "../../../components/Forms"
import { TokenAmountForm, FormValues } from "../../../components/Forms"
import { useTokenBalance } from "../../../hooks/useTokenBalance"
import { useModal } from "../../../hooks/useModal"
import { StakeData } from "../../../types/staking"
Expand All @@ -39,9 +40,9 @@ import {
} from "../../../components/Tree"
import { Divider } from "../../../components/Divider"
import { isAddressZero } from "../../../web3/utils"
import { pre as preConstants } from "../../../constants"

const StakeCard: FC<{ stake: StakeData }> = ({ stake }) => {
const formRef = useRef<FormikProps<FormValues>>(null)
const [isStakeAction, setFlag] = useBoolean(true)
const tBalance = useTokenBalance(Token.T)
const { openModal } = useModal()
Expand All @@ -52,19 +53,17 @@ const StakeCard: FC<{ stake: StakeData }> = ({ stake }) => {
!isAddressZero(stake.preConfig.operator) &&
stake.preConfig.isOperatorConfirmed

const shouldDisplayLowPREFunds =
!isAddressZero(stake.preConfig.operator) &&
!stake.preConfig.isOperatorConfirmed &&
BigNumber.from(stake.preConfig.operatorEthBalance).lt(
preConstants.LOW_FUNDS_THRESHOLD_IN_WEI
)

const submitButtonText = !isStakeAction
? "Unstake"
: isPRESet
? "Top-up"
: "Set PRE"

const onChangeAction = useCallback(() => {
formRef.current?.resetForm()
setFlag.toggle()
}, [setFlag.toggle])

const onSubmitTopUpForm = (tokenAmount: string | number) => {
openModal(ModalType.TopupT, { stake, amountTopUp: tokenAmount })
}
Expand Down Expand Up @@ -95,13 +94,7 @@ const StakeCard: FC<{ stake: StakeData }> = ({ stake }) => {
const isInActiveStake = BigNumber.from(stake.totalInTStake).isZero()

return (
<Card
borderColor={
isInActiveStake || !isPRESet || shouldDisplayLowPREFunds
? "red.200"
: undefined
}
>
<Card borderColor={isInActiveStake || !isPRESet ? "red.200" : undefined}>
<StakeCardHeader>
<Badge
colorScheme={isInActiveStake ? "gray" : "green"}
Expand All @@ -112,7 +105,7 @@ const StakeCard: FC<{ stake: StakeData }> = ({ stake }) => {
{isInActiveStake ? "inactive" : "active"}
</Badge>
<StakeCardHeaderTitle stake={stake} />
<Switcher onClick={setFlag.toggle} isActive={isStakeAction} />
<Switcher onClick={onChangeAction} isActive={isStakeAction} />
</StakeCardHeader>
<Body2 mt="10" mb="4">
Staking Bonus
Expand All @@ -129,11 +122,6 @@ const StakeCard: FC<{ stake: StakeData }> = ({ stake }) => {
missing PRE
</Badge>
)}
{shouldDisplayLowPREFunds && (
<Badge bg={"red.400"} variant="solid" size="medium" ml="3">
low PRE funds
</Badge>
)}
</Flex>
<Divider mb="0" />
{hasLegacyStakes ? (
Expand Down Expand Up @@ -161,13 +149,14 @@ const StakeCard: FC<{ stake: StakeData }> = ({ stake }) => {
</Flex>
{isStakeAction || !hasLegacyStakes ? (
<TokenAmountForm
innerRef={formRef}
onSubmitForm={onSubmitForm}
label={`${isStakeAction ? "Stake" : "Unstake"} Amount`}
submitButtonText={submitButtonText}
maxTokenAmount={isStakeAction ? tBalance : stake.tStake}
shouldDisplayMaxAmountInLabel
isDisabled={!isPRESet}
shouldValidateForm={isPRESet}
isDisabled={isStakeAction && !isPRESet}
shouldValidateForm={!isStakeAction || isPRESet}
/>
) : (
<Button onClick={onSubmitUnstakeBtn} isFullWidth>
Expand Down
3 changes: 2 additions & 1 deletion src/store/staking/stakingSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ export const stakingSlice = createSlice({
operator: AddressZero,
isOperatorConfirmed: false,
operatorStartTimestamp: "0",
operatorEthBalance: "0",
}

state.stakes = [newStake, ...state.stakes]
Expand Down Expand Up @@ -147,6 +146,8 @@ export const stakingSlice = createSlice({
.add(BigNumber.from(stake.nuInTStake))
.toString()

stakes[stakeIdxToUpdate].totalInTStake = totalInTStake

const _isBeforeOrEqualBonusDeadline = isBeforeOrEqualBonusDeadline()
const eligibleStakeAmount = _isBeforeOrEqualBonusDeadline
? totalInTStake
Expand Down
1 change: 0 additions & 1 deletion src/types/staking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export interface PreConfig {
operator: string
isOperatorConfirmed: boolean
operatorStartTimestamp: string
operatorEthBalance: string
}

export interface PreConfigData {
Expand Down

0 comments on commit 63ae1e9

Please sign in to comment.