Skip to content

Commit

Permalink
Deprecates redux fromValue in favor of local input component behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
abtestingalpha committed Aug 15, 2024
1 parent 8251989 commit 9db21b1
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 192 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ const DestinationAddress = () => {
}

const Slippage = () => {
const { fromValue } = useBridgeState()
const { debouncedFromValue } = useBridgeState()

const {
bridgeQuote: { exchangeRate },
} = useBridgeQuoteState()

const { formattedPercentSlippage, safeFromAmount, underFee, textColor } =
useExchangeRateInfo(fromValue, exchangeRate)
useExchangeRateInfo(debouncedFromValue, exchangeRate)
return (
<div className="flex justify-between">
<span className="text-zinc-500 dark:text-zinc-400">Slippage</span>
Expand Down Expand Up @@ -169,9 +169,9 @@ const GasDropLabel = () => {
)
}

const useExchangeRateInfo = (fromValue, exchangeRate) => {
const useExchangeRateInfo = (value, exchangeRate) => {
const safeExchangeRate = typeof exchangeRate === 'bigint' ? exchangeRate : 0n
const safeFromAmount = fromValue ?? '0'
const safeFromAmount = value ?? '0'

const formattedExchangeRate = formatBigIntToString(safeExchangeRate, 18, 4)
const numExchangeRate = Number(formattedExchangeRate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const BridgeTransactionButton = ({
const {
destinationAddress,
fromToken,
fromValue,
debouncedFromValue,
toToken,
fromChainId,
toChainId,
Expand All @@ -61,24 +61,26 @@ export const BridgeTransactionButton = ({
const sufficientBalance = useMemo(() => {
if (!fromChainId || !fromToken || !toChainId || !toToken) return false
return (
stringToBigInt(fromValue, fromToken?.decimals[fromChainId]) <=
stringToBigInt(debouncedFromValue, fromToken?.decimals[fromChainId]) <=
balanceForToken
)
}, [balanceForToken, fromValue, fromChainId, toChainId, toToken])
}, [balanceForToken, debouncedFromValue, fromChainId, toChainId, toToken])

const fromTokenDecimals: number | undefined =
fromToken && fromToken?.decimals[fromChainId]

const fromValueBigInt = useMemo(() => {
return fromTokenDecimals ? stringToBigInt(fromValue, fromTokenDecimals) : 0
}, [fromValue, fromTokenDecimals])
const debouncedFromValueBigInt = useMemo(() => {
return fromTokenDecimals
? stringToBigInt(debouncedFromValue, fromTokenDecimals)
: 0
}, [debouncedFromValue, fromTokenDecimals])

const bridgeQuoteAmountGreaterThanInputForRfq = useMemo(() => {
return (
bridgeQuote.bridgeModuleName === 'SynapseRFQ' &&
bridgeQuote.outputAmount > fromValueBigInt
bridgeQuote.outputAmount > debouncedFromValueBigInt
)
}, [bridgeQuote.outputAmount, fromValueBigInt])
}, [bridgeQuote.outputAmount, debouncedFromValueBigInt])

const chainSelectionsMatchBridgeQuote = useMemo(() => {
return (
Expand Down Expand Up @@ -127,7 +129,7 @@ export const BridgeTransactionButton = ({
} else if (
!isLoading &&
bridgeQuote?.feeAmount === 0n &&
fromValueBigInt > 0
debouncedFromValueBigInt > 0
) {
buttonProperties = {
label: `Amount must be greater than fee`,
Expand All @@ -136,7 +138,7 @@ export const BridgeTransactionButton = ({
} else if (
!isLoading &&
!chainSelectionsMatchBridgeQuote &&
fromValueBigInt > 0
debouncedFromValueBigInt > 0
) {
buttonProperties = {
label: 'Please reset chain selection',
Expand All @@ -145,13 +147,13 @@ export const BridgeTransactionButton = ({
} else if (
!isLoading &&
bridgeQuoteAmountGreaterThanInputForRfq &&
fromValueBigInt > 0
debouncedFromValueBigInt > 0
) {
buttonProperties = {
label: 'Invalid bridge quote',
onClick: null,
}
} else if (!isConnected && fromValueBigInt > 0) {
} else if (!isConnected && debouncedFromValueBigInt > 0) {
buttonProperties = {
label: `Connect Wallet to Bridge`,
onClick: openConnectModal,
Expand All @@ -171,13 +173,17 @@ export const BridgeTransactionButton = ({
onClick: () => dispatch(setIsDestinationWarningAccepted(true)),
className: '!from-bgLight !to-bgLight',
}
} else if (chain?.id != fromChainId && fromValueBigInt > 0) {
} else if (chain?.id != fromChainId && debouncedFromValueBigInt > 0) {
buttonProperties = {
label: `Switch to ${chains.find((c) => c.id === fromChainId)?.name}`,
onClick: () => switchChain({ chainId: fromChainId }),
pendingLabel: 'Switching chains',
}
} else if (!isApproved && fromValueBigInt > 0 && bridgeQuote?.destQuery) {
} else if (
!isApproved &&
debouncedFromValueBigInt > 0 &&
bridgeQuote?.destQuery
) {
buttonProperties = {
onClick: approveTxn,
label: `Approve ${fromToken?.symbol}`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { setFromChainId } from '@/slices/bridge/reducer'
import { ChainSelector } from '@/components/ui/ChainSelector'
import { CHAINS_BY_ID } from '@/constants/chains'
import { useFromChainListArray } from './hooks/useFromChainListArray'
import { useBridgeState } from '@/slices/bridge/hooks'
import { useWalletState } from '@/slices/wallet/hooks'

export const FromChainSelector = () => {
const { fromChainId } = useBridgeState()
const { isWalletPending } = useWalletState()

return (
<ChainSelector
dataTestId="bridge-origin-chain"
selectedItem={CHAINS_BY_ID[fromChainId]}
isOrigin={true}
label="From"
itemListFunction={useFromChainListArray}
setFunction={setFromChainId}
action="Bridge"
disabled={isWalletPending}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { setFromToken } from '@/slices/bridge/reducer'
import { TokenSelector } from '@/components/ui/TokenSelector'
import { useBridgeState } from '@/slices/bridge/hooks'
import { useFromTokenListArray } from './hooks/useFromTokenListArray'
import { useWalletState } from '@/slices/wallet/hooks'

export const FromTokenSelector = () => {
const { fromToken } = useBridgeState()
const { isWalletPending } = useWalletState()

return (
<TokenSelector
dataTestId="bridge-origin-token"
selectedItem={fromToken}
isOrigin={true}
placeholder="Out"
itemListFunction={useFromTokenListArray}
setFunction={setFromToken}
action="Bridge"
disabled={isWalletPending}
/>
)
}
Original file line number Diff line number Diff line change
@@ -1,48 +1,39 @@
import { isNull, isNumber } from 'lodash'
import { debounce, isNull, isNumber } from 'lodash'
import toast from 'react-hot-toast'
import React, { useEffect, useState, useCallback, useMemo } from 'react'
import { useAccount } from 'wagmi'
import { useAppDispatch } from '@/store/hooks'
import {
initialState,
updateFromValue,
setFromChainId,
setFromToken,
} from '@/slices/bridge/reducer'
import { ChainSelector } from '@/components/ui/ChainSelector'
import { TokenSelector } from '@/components/ui/TokenSelector'
import { updateDebouncedFromValue } from '@/slices/bridge/reducer'
import { AmountInput } from '@/components/ui/AmountInput'
import { cleanNumberInput } from '@/utils/cleanNumberInput'
import {
ConnectToNetworkButton,
ConnectWalletButton,
ConnectedIndicator,
} from '@/components/ConnectionIndicators'
import { CHAINS_BY_ID } from '@/constants/chains'
import { useFromChainListArray } from './hooks/useFromChainListArray'
import { useBridgeState } from '@/slices/bridge/hooks'
import { usePortfolioState } from '@/slices/portfolio/hooks'
import { BridgeSectionContainer } from '@/components/ui/BridgeSectionContainer'
import { BridgeAmountContainer } from '@/components/ui/BridgeAmountContainer'
import { useFromTokenListArray } from './hooks/useFromTokenListArray'
import { AvailableBalance } from './AvailableBalance'
import { useGasEstimator } from '../../utils/hooks/useGasEstimator'
import { getParsedBalance } from '@/utils/getParsedBalance'
import { MaxButton } from './MaxButton'
import { formatAmount } from '../../utils/formatAmount'
import { useWalletState } from '@/slices/wallet/hooks'
import { FromChainSelector } from '@/components/StateManagedBridge/FromChainSelector'
import { FromTokenSelector } from '@/components/StateManagedBridge/FromTokenSelector'

export const inputRef = React.createRef<HTMLInputElement>()

export const InputContainer = () => {
const dispatch = useAppDispatch()
const { chain, isConnected } = useAccount()
const { balances } = usePortfolioState()
const { fromChainId, toChainId, fromToken, toToken, fromValue } =
const { fromChainId, toChainId, fromToken, toToken, debouncedFromValue } =
useBridgeState()
const { isWalletPending } = useWalletState()
const [showValue, setShowValue] = useState('')
const [hasMounted, setHasMounted] = useState(false)
const [localInputValue, setLocalInputValue] = useState(debouncedFromValue)

const { addresses, decimals } = fromToken || {}
const tokenDecimals = isNumber(decimals) ? decimals : decimals?.[fromChainId]
Expand Down Expand Up @@ -70,27 +61,58 @@ export const InputContainer = () => {
} = useGasEstimator()

const isInputMax =
maxBridgeableGas?.toString() === fromValue || parsedBalance === fromValue
maxBridgeableGas?.toString() === debouncedFromValue ||
parsedBalance === debouncedFromValue

const debouncedUpdateFromValue = useMemo(
() =>
debounce(
(value: string) => dispatch(updateDebouncedFromValue(value)),
300
),
[dispatch]
)

useEffect(() => {
return () => {
debouncedUpdateFromValue.cancel()
}
}, [debouncedUpdateFromValue])

const handleFromValueChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const cleanedValue = cleanNumberInput(event.target.value)
setLocalInputValue(cleanedValue)
debouncedUpdateFromValue(cleanedValue)
},
[debouncedUpdateFromValue]
)

const onMaxBalance = useCallback(async () => {
if (hasValidGasEstimateInputs()) {
const bridgeableBalance = await estimateBridgeableBalanceCallback()

if (isNull(bridgeableBalance)) {
dispatch(updateFromValue(parsedBalance))
setLocalInputValue(parsedBalance)
dispatch(updateDebouncedFromValue(parsedBalance))
} else if (bridgeableBalance > 0) {
dispatch(updateFromValue(bridgeableBalance?.toString()))
const bridgeableBalanceString = bridgeableBalance.toString()
setLocalInputValue(bridgeableBalanceString)
dispatch(updateDebouncedFromValue(bridgeableBalanceString))
} else {
dispatch(updateFromValue('0.0'))
setLocalInputValue('0.0')
dispatch(updateDebouncedFromValue('0.0'))
toast.error('Gas fees likely exceeds your balance.', {
id: 'toast-error-not-enough-gas',
duration: 10000,
})
}
} else {
dispatch(updateFromValue(parsedBalance))
setLocalInputValue(parsedBalance)
dispatch(updateDebouncedFromValue(parsedBalance))
}
}, [
dispatch,
fromChainId,
fromToken,
parsedBalance,
Expand All @@ -99,47 +121,18 @@ export const InputContainer = () => {
])

useEffect(() => {
setHasMounted(true)
}, [])
setLocalInputValue(debouncedFromValue)
}, [debouncedFromValue])

const connectedStatus = useMemo(() => {
if (hasMounted && !isConnected) {
if (!isConnected) {
return <ConnectWalletButton />
} else if (hasMounted && isConnected && fromChainId === chain?.id) {
} else if (isConnected && fromChainId === chain?.id) {
return <ConnectedIndicator />
} else if (hasMounted && isConnected && fromChainId !== chain?.id) {
} else if (isConnected && fromChainId !== chain?.id) {
return <ConnectToNetworkButton chainId={fromChainId} />
}
}, [chain, fromChainId, isConnected, hasMounted])

useEffect(() => {
if (fromToken && tokenDecimals) {
setShowValue(fromValue)
}

if (fromValue === initialState.fromValue) {
setShowValue(initialState.fromValue)
}
}, [fromValue, inputRef, fromChainId, fromToken])

const handleFromValueChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const fromValueString: string = cleanNumberInput(event.target.value)
try {
dispatch(updateFromValue(fromValueString))
setShowValue(fromValueString)
} catch (error) {
console.error('Invalid value for conversion to BigInteger')
const inputValue = event.target.value
const regex = /^[0-9]*[.,]?[0-9]*$/

if (regex.test(inputValue) || inputValue === '') {
dispatch(updateFromValue(inputValue))
setShowValue(inputValue)
}
}
}
}, [chain, fromChainId, isConnected])

return (
<BridgeSectionContainer>
Expand All @@ -152,7 +145,7 @@ export const InputContainer = () => {
<div className="flex flex-wrap w-full">
<AmountInput
inputRef={inputRef}
showValue={showValue}
showValue={localInputValue}
handleFromValueChange={handleFromValueChange}
disabled={isWalletPending}
/>
Expand All @@ -179,39 +172,3 @@ export const InputContainer = () => {
</BridgeSectionContainer>
)
}

const FromChainSelector = () => {
const { fromChainId } = useBridgeState()
const { isWalletPending } = useWalletState()

return (
<ChainSelector
dataTestId="bridge-origin-chain"
selectedItem={CHAINS_BY_ID[fromChainId]}
isOrigin={true}
label="From"
itemListFunction={useFromChainListArray}
setFunction={setFromChainId}
action="Bridge"
disabled={isWalletPending}
/>
)
}

const FromTokenSelector = () => {
const { fromToken } = useBridgeState()
const { isWalletPending } = useWalletState()

return (
<TokenSelector
dataTestId="bridge-origin-token"
selectedItem={fromToken}
isOrigin={true}
placeholder="Out"
itemListFunction={useFromTokenListArray}
setFunction={setFromToken}
action="Bridge"
disabled={isWalletPending}
/>
)
}
Loading

0 comments on commit 9db21b1

Please sign in to comment.