Skip to content

Commit

Permalink
Fe/format amount (#2598)
Browse files Browse the repository at this point in the history
* formatAmount util function, use rounded shortened values in Bridge/Swap Input

* Update Bridge/Swap page with parsed / formatted balances

* Clean imports
  • Loading branch information
bigboydiamonds authored May 8, 2024
1 parent 11f31ee commit f274044
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { getParsedBalance } from '@/utils/getParsedBalance'
import { useGasEstimator } from '@/utils/hooks/useGasEstimator'
import GasIcon from '@/components/icons/GasIcon'
import { trimTrailingZeroesAfterDecimal } from '@/utils/trimTrailingZeroesAfterDecimal'
import { formatAmount } from '@/utils/formatAmount'
import { formatBigIntToString } from '@/utils/bigint/format'

const handleFocusOnBridgeInput = () => {
inputRef.current?.focus()
Expand All @@ -39,8 +41,8 @@ export const PortfolioTokenAsset = ({
? decimals
: decimals[portfolioChainId]

const parsedBalance = getParsedBalance(balance, tokenDecimals, 4)
const parsedBalanceLong = getParsedBalance(balance, tokenDecimals, 8)
const parsedBalance = getParsedBalance(balance, tokenDecimals)
const formattedBalance = formatAmount(parsedBalance)

const isDisabled = false
const isPortfolioChainSelected = fromChainId === portfolioChainId
Expand Down Expand Up @@ -80,13 +82,13 @@ export const PortfolioTokenAsset = ({
</div>
) : (
<div className="whitespace-nowrap">
{parsedBalanceLong} {symbol}
{parsedBalance} {symbol}
</div>
)
}
>
<div>
{parsedBalance} {symbol}
{formattedBalance} {symbol}
</div>
</HoverTooltip>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
import { ChainSelector } from '@/components/ui/ChainSelector'
import { TokenSelector } from '@/components/ui/TokenSelector'
import { AmountInput } from '@/components/ui/AmountInput'
import { formatBigIntToString } from '@/utils/bigint/format'
import { cleanNumberInput } from '@/utils/cleanNumberInput'
import {
ConnectToNetworkButton,
Expand All @@ -30,6 +29,7 @@ import { AvailableBalance } from './AvailableBalance'
import { useGasEstimator } from '../../utils/hooks/useGasEstimator'
import { getParsedBalance } from '@/utils/getParsedBalance'
import { MaxButton } from './MaxButton'
import { formatAmount } from '../../utils/formatAmount'

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

Expand All @@ -47,8 +47,8 @@ export const InputContainer = () => {
const balance: bigint = balances[fromChainId]?.find(
(token) => token.tokenAddress === addresses?.[fromChainId]
)?.balance
const parsedBalance = getParsedBalance(balance, tokenDecimals, 4)
const fullParsedBalance = formatBigIntToString(balance, tokenDecimals)
const parsedBalance = getParsedBalance(balance, tokenDecimals)
const formattedBalance = formatAmount(parsedBalance)

const hasValidFromSelections: boolean = useMemo(() => {
return Boolean(fromChainId && fromToken)
Expand All @@ -68,15 +68,14 @@ export const InputContainer = () => {
} = useGasEstimator()

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

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

if (isNull(bridgeableBalance)) {
dispatch(updateFromValue(fullParsedBalance))
dispatch(updateFromValue(parsedBalance))
} else if (bridgeableBalance > 0) {
dispatch(updateFromValue(bridgeableBalance?.toString()))
} else {
Expand All @@ -87,12 +86,12 @@ export const InputContainer = () => {
})
}
} else {
dispatch(updateFromValue(fullParsedBalance))
dispatch(updateFromValue(parsedBalance))
}
}, [
fromChainId,
fromToken,
fullParsedBalance,
parsedBalance,
hasValidGasEstimateInputs,
estimateBridgeableBalanceCallback,
])
Expand Down Expand Up @@ -156,7 +155,7 @@ export const InputContainer = () => {
/>
<div className="flex items-center">
<AvailableBalance
balance={parsedBalance}
balance={formattedBalance}
maxBridgeableBalance={maxBridgeableGas}
gasCost={parsedGasCost}
isGasToken={isGasToken}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import { AmountInput } from '@/components/ui/AmountInput'
import { joinClassNames } from '@/utils/joinClassNames'
import { MaxButton } from '../StateManagedBridge/MaxButton'
import { trimTrailingZeroesAfterDecimal } from '@/utils/trimTrailingZeroesAfterDecimal'
import { formatAmount } from '@/utils/formatAmount'
import { getParsedBalance } from '@/utils/getParsedBalance'

export const SwapInputContainer = () => {
const inputRef = useRef<HTMLInputElement>(null)
Expand All @@ -53,14 +55,12 @@ export const SwapInputContainer = () => {
(token) => token.tokenAddress === swapFromToken?.addresses[swapChainId]
)

const parsedBalance = tokenData?.parsedBalance
const balance = tokenData?.balance
const parsedFullBalance = formatBigIntToString(
balance,
tokenData?.token?.decimals[swapChainId]
)
const decimals = tokenData?.token?.decimals[swapChainId]
const parsedBalance = getParsedBalance(balance, decimals)
const formattedBalance = formatAmount(parsedBalance)

const isInputMax = parsedFullBalance === swapFromValue
const isInputMax = parsedBalance === swapFromValue

useEffect(() => {
if (
Expand Down Expand Up @@ -143,7 +143,7 @@ export const SwapInputContainer = () => {
<span className="text-zinc-500 dark:text-zinc-400">
Available:{' '}
</span>
{parsedBalance ?? '0.0'}
{formattedBalance ?? '0.0'}
</label>
<MaxButton
onClick={onMaxBalance}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _ from 'lodash'
import { memo, useEffect, useRef } from 'react'
import { memo, useRef } from 'react'
import Image from 'next/image'

import { type Token, type ActionTypes } from '@/utils/types'
Expand All @@ -10,6 +10,8 @@ import { findChainIdsWithPausedToken } from '@/constants/tokens'
import { getActiveStyleForButton, getHoverStyleForButton } from '@/styles/hover'
import { joinClassNames } from '@/utils/joinClassNames'
import { useSwapState } from '@/slices/swap/hooks'
import { formatAmount } from '@/utils/formatAmount'
import { getParsedBalance } from '@/utils/getParsedBalance'

export const SelectSpecificTokenButton = ({
showAllChains,
Expand Down Expand Up @@ -81,17 +83,21 @@ const ButtonContent = memo(
}) => {
const portfolioBalances = usePortfolioBalances()

const parsedBalance = portfolioBalances[chainId]?.find(
const tokenData = portfolioBalances[chainId]?.find(
(tb) => tb.token.addresses[chainId] === token.addresses[chainId]
)?.parsedBalance
)
const decimals = tokenData?.token?.decimals[chainId]
const balance = tokenData?.balance
const parsedBalance = getParsedBalance(balance, decimals)
const formattedBalance = formatAmount(parsedBalance)

return (
<div data-test-id="button-content" className="">
<Coin
token={token}
showAllChains={showAllChains}
isOrigin={isOrigin}
parsedBalance={parsedBalance}
parsedBalance={formattedBalance}
/>
</div>
)
Expand Down
69 changes: 69 additions & 0 deletions packages/synapse-interface/utils/formatAmount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
interface FormatOptions {
fullAmount?: boolean
standardDigits?: number
useCompactNotation?: boolean
compactDigits?: number
minimumAmount?: number
roundingMode?: string
}

export const formatAmount = (
amount: string,
options?: FormatOptions
): string => {
if (amount === '') return ''

const floatAmount = parseFloat(amount)

try {
if (!Number.isFinite(floatAmount)) {
throw new TypeError(`"${amount}" is not a finite number`)
}
} catch ({ name, message }) {
console.error(name, message)
return amount
}

const fullAmount = options?.fullAmount ?? false
const standardDigits = options?.standardDigits ?? 4
const useCompactNotation = options?.useCompactNotation ?? true
const compactDigits = options?.compactDigits ?? useCompactNotation ? 2 : 0
const minimumAmount = options?.minimumAmount ?? 0.0001

const locales = 'en-UK'

if (!floatAmount) return '0.0'

if (fullAmount) return Intl.NumberFormat(locales).format(floatAmount)

if (floatAmount < minimumAmount) return `< ${minimumAmount}`

const absAmount = Math.abs(floatAmount)

if (absAmount < 0.0001)
return Intl.NumberFormat(locales, {
maximumSignificantDigits: 1,
}).format(floatAmount)

if (absAmount < 1)
return Intl.NumberFormat(locales, {
minimumFractionDigits: standardDigits,
}).format(floatAmount)

if (absAmount < 1000)
return Intl.NumberFormat(locales, {
minimumSignificantDigits: standardDigits,
maximumSignificantDigits: standardDigits,
}).format(floatAmount)

if (absAmount < 1000000)
return Intl.NumberFormat(locales, {
maximumFractionDigits: 0,
}).format(floatAmount)

return Intl.NumberFormat(locales, {
minimumFractionDigits: compactDigits,
maximumFractionDigits: compactDigits,
notation: useCompactNotation ? 'compact' : 'standard',
}).format(floatAmount)
}
9 changes: 4 additions & 5 deletions packages/synapse-interface/utils/getParsedBalance.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { trimTrailingZeroesAfterDecimal } from '@/utils/trimTrailingZeroesAfterDecimal'
import { formatBigIntToString } from './bigint/format'
import { hasOnlyZeroes } from './hasOnlyZeroes'

export const getParsedBalance = (
balance: bigint,
decimals: number,
places?: number
) => {
const formattedBalance = formatBigIntToString(balance, decimals, places)
const verySmallBalance = balance > 0n && hasOnlyZeroes(formattedBalance)

return verySmallBalance ? '< 0.001' : formattedBalance
return trimTrailingZeroesAfterDecimal(
formatBigIntToString(balance, decimals, places)
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const trimTrailingZeroesAfterDecimal = (input: string): string => {
const parts = input?.split('.')

if (parts.length === 2) {
if (parts?.length === 2) {
const integerPart = parts[0]
let fractionalPart = parts[1]

Expand Down

0 comments on commit f274044

Please sign in to comment.