Merge pull request #72 from blockworks-foundation/format-numeric-value
format numeric value component
This commit is contained in:
commit
8c53d278a5
|
@ -21,11 +21,6 @@ import {
|
|||
INPUT_TOKEN_DEFAULT,
|
||||
} from './../utils/constants'
|
||||
import { notify } from './../utils/notifications'
|
||||
import {
|
||||
floorToDecimal,
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
} from './../utils/numbers'
|
||||
import ActionTokenList from './account/ActionTokenList'
|
||||
import ButtonGroup from './forms/ButtonGroup'
|
||||
import Label from './forms/Label'
|
||||
|
@ -45,6 +40,8 @@ import TokenVaultWarnings from '@components/shared/TokenVaultWarnings'
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { useEnhancedWallet } from './wallet/EnhancedWalletProvider'
|
||||
import AmountWithValue from './shared/AmountWithValue'
|
||||
import FormatNumericValue from './shared/FormatNumericValue'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
|
||||
interface BorrowFormProps {
|
||||
onSuccess: () => void
|
||||
|
@ -85,17 +82,12 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) {
|
|||
const group = mangoStore.getState().group
|
||||
if (!group || !bank || !mangoAccount) return new Decimal(0)
|
||||
const amount = getMaxWithdrawForBank(group, bank, mangoAccount, true)
|
||||
return amount && amount.gt(0)
|
||||
? floorToDecimal(amount, bank.mintDecimals)
|
||||
: new Decimal(0)
|
||||
return amount && amount.gt(0) ? new Decimal(amount) : new Decimal(0)
|
||||
}, [mangoAccount, bank])
|
||||
|
||||
const tokenBalance = useMemo(() => {
|
||||
if (!bank || !mangoAccount) return new Decimal(0)
|
||||
const balance = floorToDecimal(
|
||||
mangoAccount.getTokenBalanceUi(bank),
|
||||
bank.mintDecimals
|
||||
)
|
||||
const balance = new Decimal(mangoAccount.getTokenBalanceUi(bank))
|
||||
return balance.gt(0) ? balance : new Decimal(0)
|
||||
}, [bank, mangoAccount])
|
||||
|
||||
|
@ -105,17 +97,19 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) {
|
|||
(percentage: string) => {
|
||||
if (!bank) return
|
||||
setSizePercentage(percentage)
|
||||
const amount = (Number(percentage) / 100) * (tokenMax.toNumber() || 0)
|
||||
setInputAmount(floorToDecimal(amount, bank.mintDecimals).toFixed())
|
||||
const amount = floorToDecimal(
|
||||
new Decimal(percentage).div(100).mul(tokenMax),
|
||||
bank.mintDecimals
|
||||
)
|
||||
setInputAmount(amount.toString())
|
||||
},
|
||||
[tokenMax, bank]
|
||||
)
|
||||
|
||||
const setMax = useCallback(() => {
|
||||
if (!bank) return
|
||||
setInputAmount(
|
||||
floorToDecimal(Number(tokenMax), bank.mintDecimals).toFixed()
|
||||
)
|
||||
const max = floorToDecimal(tokenMax, bank.mintDecimals)
|
||||
setInputAmount(max.toString())
|
||||
handleSizePercentage('100')
|
||||
}, [bank, tokenMax, handleSizePercentage])
|
||||
|
||||
|
@ -170,14 +164,11 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) {
|
|||
bank,
|
||||
mangoAccount,
|
||||
true
|
||||
)
|
||||
).toNumber()
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
maxAmount: floorToDecimal(
|
||||
maxAmount,
|
||||
bank.mintDecimals
|
||||
).toNumber(),
|
||||
maxAmount,
|
||||
}
|
||||
})
|
||||
: []
|
||||
|
@ -255,12 +246,10 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) {
|
|||
{bank ? (
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
decimals={bank.mintDecimals}
|
||||
label={t('max')}
|
||||
onClick={setMax}
|
||||
value={floorToDecimal(
|
||||
Number(tokenMax),
|
||||
bank.mintDecimals
|
||||
).toFixed()}
|
||||
value={tokenMax}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -332,46 +321,33 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) {
|
|||
<p>{t('withdraw-amount')}</p>
|
||||
{isBorrow ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(
|
||||
Number(tokenBalance),
|
||||
bank.mintDecimals
|
||||
)}
|
||||
value={formatFixedDecimals(
|
||||
bank.uiPrice * tokenBalance.toNumber(),
|
||||
true
|
||||
)}
|
||||
amount={tokenBalance}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={bank.uiPrice * tokenBalance.toNumber()}
|
||||
/>
|
||||
) : inputAmount ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(
|
||||
Number(inputAmount),
|
||||
bank.mintDecimals
|
||||
)}
|
||||
value={formatFixedDecimals(
|
||||
bank.uiPrice * parseFloat(inputAmount),
|
||||
true
|
||||
)}
|
||||
amount={inputAmount}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={bank.uiPrice * parseFloat(inputAmount)}
|
||||
/>
|
||||
) : (
|
||||
<AmountWithValue amount="0" value="$0.00" />
|
||||
<AmountWithValue amount="0" amountDecimals={0} value={0} />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<p>{t('borrow-amount')}</p>
|
||||
{isBorrow ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(
|
||||
Number(inputAmount) - Number(tokenBalance),
|
||||
bank.mintDecimals
|
||||
)}
|
||||
value={formatFixedDecimals(
|
||||
amount={Number(inputAmount) - Number(tokenBalance)}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={
|
||||
bank.uiPrice *
|
||||
(parseFloat(inputAmount) - tokenBalance.toNumber()),
|
||||
true
|
||||
)}
|
||||
(parseFloat(inputAmount) - tokenBalance.toNumber())
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<AmountWithValue amount="0" value="$0.00" />
|
||||
<AmountWithValue amount="0" amountDecimals={0} value={0} />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
|
@ -383,11 +359,13 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) {
|
|||
<p className="font-mono text-th-fgd-2">
|
||||
{isBorrow ? (
|
||||
<>
|
||||
{formatDecimal(
|
||||
bank.loanOriginationFeeRate.toNumber() *
|
||||
(parseFloat(inputAmount) - tokenBalance.toNumber()),
|
||||
bank.mintDecimals
|
||||
)}{' '}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
bank.loanOriginationFeeRate.toNumber() *
|
||||
(parseFloat(inputAmount) - tokenBalance.toNumber())
|
||||
}
|
||||
decimals={bank.mintDecimals}
|
||||
/>{' '}
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{bank.name}
|
||||
</span>
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
LinkIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import Decimal from 'decimal.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Image from 'next/legacy/image'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
|
@ -19,11 +18,6 @@ import {
|
|||
INPUT_TOKEN_DEFAULT,
|
||||
} from './../utils/constants'
|
||||
import { notify } from './../utils/notifications'
|
||||
import {
|
||||
floorToDecimal,
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
} from './../utils/numbers'
|
||||
import { TokenAccount } from './../utils/tokens'
|
||||
import ActionTokenList from './account/ActionTokenList'
|
||||
import ButtonGroup from './forms/ButtonGroup'
|
||||
|
@ -42,6 +36,9 @@ import useMangoGroup from 'hooks/useMangoGroup'
|
|||
import { useEnhancedWallet } from './wallet/EnhancedWalletProvider'
|
||||
import useSolBalance from 'hooks/useSolBalance'
|
||||
import AmountWithValue from './shared/AmountWithValue'
|
||||
import FormatNumericValue from './shared/FormatNumericValue'
|
||||
import Decimal from 'decimal.js'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
|
||||
interface DepositFormProps {
|
||||
onSuccess: () => void
|
||||
|
@ -128,19 +125,18 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
|
|||
}, [walletTokens, selectedToken])
|
||||
|
||||
const setMax = useCallback(() => {
|
||||
setInputAmount(
|
||||
floorToDecimal(tokenMax.maxAmount, tokenMax.maxDecimals).toFixed()
|
||||
)
|
||||
const max = floorToDecimal(tokenMax.maxAmount, tokenMax.maxDecimals)
|
||||
setInputAmount(max.toString())
|
||||
setSizePercentage('100')
|
||||
}, [tokenMax])
|
||||
|
||||
const handleSizePercentage = useCallback(
|
||||
(percentage: string) => {
|
||||
setSizePercentage(percentage)
|
||||
|
||||
let amount = new Decimal(tokenMax.maxAmount).mul(percentage).div(100)
|
||||
amount = floorToDecimal(amount, tokenMax.maxDecimals)
|
||||
|
||||
const amount = floorToDecimal(
|
||||
new Decimal(tokenMax.maxAmount).mul(percentage).div(100),
|
||||
tokenMax.maxDecimals
|
||||
)
|
||||
setInputAmount(amount.toString())
|
||||
},
|
||||
[tokenMax]
|
||||
|
@ -197,10 +193,7 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
|
|||
return {
|
||||
key,
|
||||
value,
|
||||
walletBalance: floorToDecimal(
|
||||
walletBalance.maxAmount,
|
||||
walletBalance.maxDecimals
|
||||
).toNumber(),
|
||||
walletBalance: walletBalance.maxAmount,
|
||||
walletBalanceValue: walletBalance.maxAmount * value[0].uiPrice!,
|
||||
}
|
||||
})
|
||||
|
@ -268,12 +261,10 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
|
|||
<Label text={`${t('deposit')} ${t('token')}`} />
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
decimals={tokenMax.maxDecimals}
|
||||
label={t('wallet-balance')}
|
||||
onClick={setMax}
|
||||
value={floorToDecimal(
|
||||
tokenMax.maxAmount,
|
||||
tokenMax.maxDecimals
|
||||
).toFixed()}
|
||||
value={tokenMax.maxAmount}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-input-border bg-th-input-bkg">
|
||||
|
@ -338,17 +329,12 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
|
|||
<p>{t('deposit-amount')}</p>
|
||||
{inputAmount ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(
|
||||
Number(inputAmount),
|
||||
bank.mintDecimals
|
||||
)}
|
||||
value={formatFixedDecimals(
|
||||
bank.uiPrice * Number(inputAmount),
|
||||
true
|
||||
)}
|
||||
amount={inputAmount}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={bank.uiPrice * Number(inputAmount)}
|
||||
/>
|
||||
) : (
|
||||
<AmountWithValue amount="0" value="$0.00" />
|
||||
<AmountWithValue amount="0" amountDecimals={0} value={0} />
|
||||
)}
|
||||
</div>
|
||||
{/* <div className="flex justify-between">
|
||||
|
@ -364,12 +350,14 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
|
|||
<p className="tooltip-underline">{t('collateral-value')}</p>
|
||||
</Tooltip>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{formatFixedDecimals(
|
||||
bank.uiPrice *
|
||||
<FormatNumericValue
|
||||
value={
|
||||
bank.uiPrice *
|
||||
Number(inputAmount) *
|
||||
Number(bank.initAssetWeight),
|
||||
true
|
||||
)}
|
||||
Number(bank.initAssetWeight)
|
||||
}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,11 +13,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { notify } from './../utils/notifications'
|
||||
import {
|
||||
floorToDecimal,
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
} from './../utils/numbers'
|
||||
import { formatNumericValue } from './../utils/numbers'
|
||||
import ActionTokenList from './account/ActionTokenList'
|
||||
import ButtonGroup from './forms/ButtonGroup'
|
||||
import Label from './forms/Label'
|
||||
|
@ -83,16 +79,20 @@ function RepayForm({ onSuccess, token }: RepayFormProps) {
|
|||
}, [walletTokens, selectedToken])
|
||||
|
||||
const borrowAmount = useMemo(() => {
|
||||
if (!mangoAccount || !bank) return '0'
|
||||
return formatDecimal(
|
||||
mangoAccount.getTokenBorrowsUi(bank),
|
||||
bank.mintDecimals
|
||||
)
|
||||
if (!mangoAccount || !bank) return new Decimal(0)
|
||||
const amount = new Decimal(
|
||||
mangoAccount.getTokenBorrowsUi(bank)
|
||||
).toDecimalPlaces(bank.mintDecimals, Decimal.ROUND_UP)
|
||||
return amount
|
||||
}, [bank, mangoAccount])
|
||||
|
||||
const setMax = useCallback(() => {
|
||||
if (!bank) return
|
||||
setInputAmount(borrowAmount)
|
||||
const amount = new Decimal(borrowAmount).toDecimalPlaces(
|
||||
bank.mintDecimals,
|
||||
Decimal.ROUND_UP
|
||||
)
|
||||
setInputAmount(amount.toString())
|
||||
setSizePercentage('100')
|
||||
}, [bank, borrowAmount])
|
||||
|
||||
|
@ -100,13 +100,12 @@ function RepayForm({ onSuccess, token }: RepayFormProps) {
|
|||
(percentage: string) => {
|
||||
if (!bank) return
|
||||
setSizePercentage(percentage)
|
||||
|
||||
let amount: Decimal | number = new Decimal(borrowAmount)
|
||||
const amount = new Decimal(borrowAmount)
|
||||
.mul(percentage)
|
||||
.div(100)
|
||||
amount = floorToDecimal(amount, bank.mintDecimals).toNumber()
|
||||
.toDecimalPlaces(bank.mintDecimals, Decimal.ROUND_UP)
|
||||
|
||||
setInputAmount(amount.toFixed(bank.mintDecimals))
|
||||
setInputAmount(amount.toString())
|
||||
},
|
||||
[bank, borrowAmount]
|
||||
)
|
||||
|
@ -240,12 +239,15 @@ function RepayForm({ onSuccess, token }: RepayFormProps) {
|
|||
<div className="grid grid-cols-2">
|
||||
<div className="col-span-2 flex justify-between">
|
||||
<Label text={`${t('repay')} ${t('token')}`} />
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
label={t('amount-owed')}
|
||||
onClick={setMax}
|
||||
value={borrowAmount}
|
||||
/>
|
||||
{bank ? (
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
decimals={bank.mintDecimals}
|
||||
label={t('amount-owed')}
|
||||
onClick={setMax}
|
||||
value={borrowAmount}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-input-border bg-th-input-bkg">
|
||||
<button
|
||||
|
@ -306,17 +308,12 @@ function RepayForm({ onSuccess, token }: RepayFormProps) {
|
|||
<p>{t('repayment-amount')}</p>
|
||||
{inputAmount ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(
|
||||
Number(inputAmount),
|
||||
bank.mintDecimals
|
||||
)}
|
||||
value={formatFixedDecimals(
|
||||
bank.uiPrice * Number(inputAmount),
|
||||
true
|
||||
)}
|
||||
amount={inputAmount}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={bank.uiPrice * Number(inputAmount)}
|
||||
/>
|
||||
) : (
|
||||
<AmountWithValue amount="0" value="$0.00" />
|
||||
<AmountWithValue amount="0" amountDecimals={0} value={0} />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
|
@ -324,7 +321,10 @@ function RepayForm({ onSuccess, token }: RepayFormProps) {
|
|||
<p>{t('outstanding-balance')}</p>
|
||||
</div>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{Number(borrowAmount) - Number(inputAmount)}{' '}
|
||||
{formatNumericValue(
|
||||
Number(borrowAmount) - Number(inputAmount),
|
||||
bank.mintDecimals
|
||||
)}{' '}
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{selectedToken}
|
||||
</span>
|
||||
|
|
|
@ -13,11 +13,6 @@ import { useRouter } from 'next/router'
|
|||
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useViewport } from '../hooks/useViewport'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import {
|
||||
floorToDecimal,
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
} from '../utils/numbers'
|
||||
import { breakpoints } from '../utils/theme'
|
||||
import Switch from './forms/Switch'
|
||||
import { IconButton, LinkButton } from './shared/Button'
|
||||
|
@ -36,6 +31,7 @@ import { USDC_MINT } from 'utils/constants'
|
|||
import { PublicKey } from '@solana/web3.js'
|
||||
import ActionsLinkButton from './account/ActionsLinkButton'
|
||||
import AmountWithValue from './shared/AmountWithValue'
|
||||
import FormatNumericValue from './shared/FormatNumericValue'
|
||||
|
||||
const TokenList = () => {
|
||||
const { t } = useTranslation(['common', 'token', 'trade'])
|
||||
|
@ -187,59 +183,35 @@ const TokenList = () => {
|
|||
</div>
|
||||
</Td>
|
||||
<Td className="text-right">
|
||||
{tokenBalance ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(tokenBalance, bank.mintDecimals)}
|
||||
value={formatFixedDecimals(
|
||||
tokenBalance * oraclePrice,
|
||||
true,
|
||||
true
|
||||
)}
|
||||
stacked
|
||||
/>
|
||||
) : (
|
||||
<AmountWithValue amount="0" value="$0.00" stacked />
|
||||
)}
|
||||
<AmountWithValue
|
||||
amount={tokenBalance}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={tokenBalance * oraclePrice}
|
||||
stacked
|
||||
/>
|
||||
</Td>
|
||||
<Td className="text-right">
|
||||
{inOrders ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(inOrders, bank.mintDecimals)}
|
||||
value={formatFixedDecimals(
|
||||
inOrders * oraclePrice,
|
||||
true,
|
||||
true
|
||||
)}
|
||||
stacked
|
||||
/>
|
||||
) : (
|
||||
<AmountWithValue amount="0" value="$0.00" stacked />
|
||||
)}
|
||||
<AmountWithValue
|
||||
amount={inOrders}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={inOrders * oraclePrice}
|
||||
stacked
|
||||
/>
|
||||
</Td>
|
||||
<Td className="text-right">
|
||||
{unsettled ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(unsettled, bank.mintDecimals)}
|
||||
value={formatFixedDecimals(
|
||||
unsettled * oraclePrice,
|
||||
true,
|
||||
true
|
||||
)}
|
||||
stacked
|
||||
/>
|
||||
) : (
|
||||
<AmountWithValue amount="0" value="$0.00" stacked />
|
||||
)}
|
||||
<AmountWithValue
|
||||
amount={unsettled}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={unsettled * oraclePrice}
|
||||
stacked
|
||||
/>
|
||||
</Td>
|
||||
<Td>
|
||||
<div className="flex flex-col text-right">
|
||||
<AmountWithValue
|
||||
amount={
|
||||
interestAmount
|
||||
? formatDecimal(interestAmount, bank.mintDecimals)
|
||||
: '0'
|
||||
}
|
||||
value={formatFixedDecimals(interestValue, true, true)}
|
||||
amount={interestAmount}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={interestValue}
|
||||
stacked
|
||||
/>
|
||||
</div>
|
||||
|
@ -247,16 +219,19 @@ const TokenList = () => {
|
|||
<Td>
|
||||
<div className="flex justify-end space-x-1.5">
|
||||
<p className="text-th-up">
|
||||
{formatDecimal(bank.getDepositRateUi(), 2, {
|
||||
fixed: true,
|
||||
})}
|
||||
<FormatNumericValue
|
||||
value={bank.getDepositRateUi()}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</p>
|
||||
<span className="text-th-fgd-4">|</span>
|
||||
<p className="text-th-down">
|
||||
{formatDecimal(bank.getBorrowRateUi(), 2, {
|
||||
fixed: true,
|
||||
})}
|
||||
<FormatNumericValue
|
||||
value={bank.getBorrowRateUi()}
|
||||
decimals={2}
|
||||
roundUp
|
||||
/>
|
||||
%
|
||||
</p>
|
||||
</div>
|
||||
|
@ -322,15 +297,10 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
|
|||
const interestValue = hasInterestEarned
|
||||
? hasInterestEarned.borrow_interest_usd * -1 +
|
||||
hasInterestEarned.deposit_interest_usd
|
||||
: 0.0
|
||||
|
||||
const tokenBalance = mangoAccount
|
||||
? floorToDecimal(
|
||||
mangoAccount.getTokenBalanceUi(bank),
|
||||
bank.mintDecimals
|
||||
).toNumber()
|
||||
: 0
|
||||
|
||||
const tokenBalance = mangoAccount ? mangoAccount.getTokenBalanceUi(bank) : 0
|
||||
|
||||
const inOrders = spotBalances[bank.mint.toString()]?.inOrders || 0
|
||||
|
||||
const unsettled = spotBalances[bank.mint.toString()]?.unsettled || 0
|
||||
|
@ -356,9 +326,10 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
|
|||
<span className="mr-1 font-body text-th-fgd-4">
|
||||
{t('balance')}:
|
||||
</span>
|
||||
{tokenBalance
|
||||
? formatDecimal(tokenBalance, bank.mintDecimals)
|
||||
: '0'}
|
||||
<FormatNumericValue
|
||||
value={tokenBalance}
|
||||
decimals={bank.mintDecimals}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -391,41 +362,45 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
|
|||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">{t('trade:in-orders')}</p>
|
||||
<AmountWithValue
|
||||
amount={
|
||||
inOrders ? formatDecimal(inOrders, bank.mintDecimals) : '0'
|
||||
}
|
||||
value={formatFixedDecimals(inOrders * oraclePrice, true, true)}
|
||||
amount={inOrders}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={inOrders * oraclePrice}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">{t('trade:unsettled')}</p>
|
||||
<AmountWithValue
|
||||
amount={
|
||||
unsettled ? formatDecimal(unsettled, bank.mintDecimals) : '0'
|
||||
}
|
||||
value={formatFixedDecimals(unsettled * oraclePrice, true, true)}
|
||||
amount={unsettled}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={unsettled * oraclePrice}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">{t('interest-earned-paid')}</p>
|
||||
<AmountWithValue
|
||||
amount={
|
||||
interestAmount
|
||||
? formatDecimal(interestAmount, bank.mintDecimals)
|
||||
: '0'
|
||||
}
|
||||
value={formatFixedDecimals(interestValue, true, true)}
|
||||
amount={interestAmount}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={interestValue}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">{t('rates')}</p>
|
||||
<p className="space-x-2 font-mono">
|
||||
<span className="text-th-up">
|
||||
{formatDecimal(bank.getDepositRate().toNumber(), 2)}%
|
||||
<FormatNumericValue
|
||||
value={bank.getDepositRateUi()}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
<span className="font-normal text-th-fgd-4">|</span>
|
||||
<span className="text-th-down">
|
||||
{formatDecimal(bank.getBorrowRate().toNumber(), 2)}%
|
||||
<FormatNumericValue
|
||||
value={bank.getBorrowRateUi()}
|
||||
decimals={2}
|
||||
roundUp
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -18,11 +18,6 @@ import {
|
|||
INPUT_TOKEN_DEFAULT,
|
||||
} from './../utils/constants'
|
||||
import { notify } from './../utils/notifications'
|
||||
import {
|
||||
floorToDecimal,
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
} from './../utils/numbers'
|
||||
import ActionTokenList from './account/ActionTokenList'
|
||||
import ButtonGroup from './forms/ButtonGroup'
|
||||
import Label from './forms/Label'
|
||||
|
@ -41,6 +36,7 @@ import TokenVaultWarnings from '@components/shared/TokenVaultWarnings'
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { useEnhancedWallet } from './wallet/EnhancedWalletProvider'
|
||||
import AmountWithValue from './shared/AmountWithValue'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
|
||||
interface WithdrawFormProps {
|
||||
onSuccess: () => void
|
||||
|
@ -81,21 +77,29 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
|
|||
if (!bank || !mangoAccount || !group) return new Decimal(0)
|
||||
const amount = getMaxWithdrawForBank(group, bank, mangoAccount)
|
||||
|
||||
return amount && amount.gt(0)
|
||||
? floorToDecimal(amount, bank.mintDecimals)
|
||||
: new Decimal(0)
|
||||
return amount
|
||||
}, [mangoAccount, bank, group])
|
||||
|
||||
const handleSizePercentage = useCallback(
|
||||
(percentage: string) => {
|
||||
if (!bank) return
|
||||
setSizePercentage(percentage)
|
||||
const amount = tokenMax.mul(Number(percentage) / 100)
|
||||
setInputAmount(floorToDecimal(amount, bank.mintDecimals).toFixed())
|
||||
const amount = floorToDecimal(
|
||||
new Decimal(tokenMax).mul(percentage).div(100),
|
||||
bank.mintDecimals
|
||||
)
|
||||
setInputAmount(amount.toString())
|
||||
},
|
||||
[bank, tokenMax]
|
||||
)
|
||||
|
||||
const setMax = useCallback(() => {
|
||||
if (!bank) return
|
||||
const max = floorToDecimal(tokenMax, bank.mintDecimals)
|
||||
setInputAmount(max.toString())
|
||||
setSizePercentage('100')
|
||||
}, [bank, tokenMax])
|
||||
|
||||
const handleWithdraw = useCallback(async () => {
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
|
@ -145,16 +149,14 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
|
|||
group,
|
||||
bank,
|
||||
mangoAccount
|
||||
)
|
||||
).toNumber()
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
accountBalance: accountBalance
|
||||
? floorToDecimal(accountBalance, bank.mintDecimals).toNumber()
|
||||
: 0,
|
||||
accountBalance,
|
||||
accountBalanceValue:
|
||||
accountBalance && bank.uiPrice
|
||||
? accountBalance.toNumber() * bank.uiPrice
|
||||
? accountBalance * bank.uiPrice
|
||||
: 0,
|
||||
}
|
||||
})
|
||||
|
@ -225,12 +227,10 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
|
|||
{bank ? (
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
decimals={bank.mintDecimals}
|
||||
label={t('max')}
|
||||
onClick={() => handleSizePercentage('100')}
|
||||
value={floorToDecimal(
|
||||
Number(tokenMax),
|
||||
bank.mintDecimals
|
||||
).toFixed()}
|
||||
onClick={setMax}
|
||||
value={tokenMax}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -295,17 +295,12 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
|
|||
<p>{t('withdraw-amount')}</p>
|
||||
{inputAmount ? (
|
||||
<AmountWithValue
|
||||
amount={formatDecimal(
|
||||
Number(inputAmount),
|
||||
bank.mintDecimals
|
||||
)}
|
||||
value={formatFixedDecimals(
|
||||
bank.uiPrice * Number(inputAmount),
|
||||
true
|
||||
)}
|
||||
amount={inputAmount}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={bank.uiPrice * Number(inputAmount)}
|
||||
/>
|
||||
) : (
|
||||
<AmountWithValue amount="0" value="$0.00" />
|
||||
<AmountWithValue amount="0" amountDecimals={0} value={0} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { useTranslation } from 'next-i18next'
|
|||
import { useEffect, useMemo, useState } from 'react'
|
||||
import AccountActions from './AccountActions'
|
||||
import mangoStore, { PerformanceDataItem } from '@store/mangoStore'
|
||||
import { formatDecimal, formatFixedDecimals } from '../../utils/numbers'
|
||||
import { formatNumericValue } from '../../utils/numbers'
|
||||
import FlipNumbers from 'react-flip-numbers'
|
||||
import dynamic from 'next/dynamic'
|
||||
const SimpleAreaChart = dynamic(
|
||||
|
@ -41,6 +41,7 @@ import { useViewport } from 'hooks/useViewport'
|
|||
import { breakpoints } from 'utils/theme'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import PnlHistoryModal from '@components/modals/PnlHistoryModal'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
const AccountPage = () => {
|
||||
const { t } = useTranslation(['common', 'account'])
|
||||
|
@ -251,7 +252,7 @@ const AccountPage = () => {
|
|||
play
|
||||
delay={0.05}
|
||||
duration={1}
|
||||
numbers={formatFixedDecimals(accountValue, true, true)}
|
||||
numbers={formatNumericValue(accountValue, 2, true)}
|
||||
/>
|
||||
) : (
|
||||
<FlipNumbers
|
||||
|
@ -264,14 +265,15 @@ const AccountPage = () => {
|
|||
/>
|
||||
)
|
||||
) : (
|
||||
<span>{formatFixedDecimals(accountValue, true, true)}</span>
|
||||
<FormatNumericValue
|
||||
value={accountValue}
|
||||
isUsd={true}
|
||||
decimals={2}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center space-x-1.5">
|
||||
<Change
|
||||
change={Number(formatDecimal(accountValueChange, 2))}
|
||||
prefix="$"
|
||||
/>
|
||||
<Change change={accountValueChange} prefix="$" />
|
||||
<p className="text-th-fgd-4">{t('today')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -388,15 +390,17 @@ const AccountPage = () => {
|
|||
</p>
|
||||
</Tooltip>
|
||||
<p className="mt-1 mb-0.5 text-2xl font-bold text-th-fgd-1 lg:text-xl xl:text-2xl">
|
||||
{group && mangoAccount
|
||||
? formatFixedDecimals(
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount.getCollateralValue(group).toNumber()
|
||||
),
|
||||
false,
|
||||
true
|
||||
)
|
||||
: `$${(0).toFixed(2)}`}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
group && mangoAccount
|
||||
? toUiDecimalsForQuote(
|
||||
mangoAccount.getCollateralValue(group)
|
||||
)
|
||||
: 0
|
||||
}
|
||||
decimals={2}
|
||||
isUsd={true}
|
||||
/>
|
||||
</p>
|
||||
<span className="text-xs font-normal text-th-fgd-4">
|
||||
<Tooltip
|
||||
|
@ -407,17 +411,17 @@ const AccountPage = () => {
|
|||
>
|
||||
<span className="tooltip-underline">{t('total')}</span>:
|
||||
<span className="ml-1 font-mono text-th-fgd-2">
|
||||
{group && mangoAccount
|
||||
? formatFixedDecimals(
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount
|
||||
.getAssetsValue(group, HealthType.init)
|
||||
.toNumber()
|
||||
),
|
||||
false,
|
||||
true
|
||||
)
|
||||
: `$${(0).toFixed(2)}`}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
group && mangoAccount
|
||||
? toUiDecimalsForQuote(
|
||||
mangoAccount.getAssetsValue(group, HealthType.init)
|
||||
)
|
||||
: 0
|
||||
}
|
||||
decimals={2}
|
||||
isUsd={true}
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
@ -436,7 +440,7 @@ const AccountPage = () => {
|
|||
</p>
|
||||
</Tooltip>
|
||||
<p className="mt-1 text-2xl font-bold text-th-fgd-1 lg:text-xl xl:text-2xl">
|
||||
{leverage.toFixed(2)}x
|
||||
<FormatNumericValue value={leverage} decimals={2} roundUp />x
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -478,14 +482,14 @@ const AccountPage = () => {
|
|||
) : null}
|
||||
</div>
|
||||
<p className="mt-1 mb-0.5 text-left text-2xl font-bold text-th-fgd-1 lg:text-xl xl:text-2xl">
|
||||
{formatFixedDecimals(accountPnl, true, true)}
|
||||
<FormatNumericValue
|
||||
value={accountPnl}
|
||||
decimals={2}
|
||||
isUsd={true}
|
||||
/>
|
||||
</p>
|
||||
<div className="flex space-x-1">
|
||||
<Change
|
||||
change={Number(formatDecimal(oneDayPnlChange, 2))}
|
||||
prefix="$"
|
||||
size="small"
|
||||
/>
|
||||
<Change change={oneDayPnlChange} prefix="$" size="small" />
|
||||
<p className="text-xs text-th-fgd-4">{t('today')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -518,14 +522,14 @@ const AccountPage = () => {
|
|||
) : null}
|
||||
</div>
|
||||
<p className="mt-1 mb-0.5 text-2xl font-bold text-th-fgd-1 lg:text-xl xl:text-2xl">
|
||||
{formatFixedDecimals(interestTotalValue, true, true)}
|
||||
<FormatNumericValue
|
||||
value={interestTotalValue}
|
||||
decimals={2}
|
||||
isUsd={true}
|
||||
/>
|
||||
</p>
|
||||
<div className="flex space-x-1">
|
||||
<Change
|
||||
change={Number(formatDecimal(oneDayInterestChange, 2))}
|
||||
prefix="$"
|
||||
size="small"
|
||||
/>
|
||||
<Change change={oneDayInterestChange} prefix="$" size="small" />
|
||||
<p className="text-xs text-th-fgd-4">{t('today')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
import { Bank } from '@blockworks-foundation/mango-v4'
|
||||
import Image from 'next/legacy/image'
|
||||
import { useMemo } from 'react'
|
||||
import {
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
trimDecimals,
|
||||
} from '../../utils/numbers'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
const ActionTokenItem = ({
|
||||
bank,
|
||||
customValue,
|
||||
onSelect,
|
||||
roundUp,
|
||||
showBorrowRates,
|
||||
showDepositRates,
|
||||
}: {
|
||||
bank: Bank
|
||||
customValue: number
|
||||
onSelect: (x: string) => void
|
||||
roundUp?: boolean
|
||||
showBorrowRates?: boolean
|
||||
showDepositRates?: boolean
|
||||
}) => {
|
||||
|
@ -56,22 +54,24 @@ const ActionTokenItem = ({
|
|||
{showDepositRates ? (
|
||||
<div className="w-1/4 text-right font-mono">
|
||||
<p className="text-th-up">
|
||||
{formatDecimal(bank.getDepositRate().toNumber(), 2)}%
|
||||
<FormatNumericValue value={bank.getDepositRateUi()} decimals={2} />%
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
{showBorrowRates ? (
|
||||
<div className="w-1/4 text-right font-mono">
|
||||
<p className="text-th-down">
|
||||
{formatDecimal(bank.getBorrowRate().toNumber(), 2)}%
|
||||
<FormatNumericValue value={bank.getBorrowRateUi()} decimals={2} />%
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="w-1/2 pl-3 text-right">
|
||||
<p className="truncate font-mono text-th-fgd-1">
|
||||
{formatFixedDecimals(
|
||||
trimDecimals(customValue, bank.mintDecimals + 1)
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={customValue}
|
||||
decimals={bank.mintDecimals}
|
||||
roundUp={roundUp}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
@ -45,6 +45,7 @@ const ActionTokenList = ({
|
|||
customValue={bank[valueKey]}
|
||||
key={bank.value[0].name}
|
||||
onSelect={onSelect}
|
||||
roundUp={valueKey === 'borrowAmount'}
|
||||
showBorrowRates={showBorrowRates}
|
||||
showDepositRates={showDepositRates}
|
||||
/>
|
||||
|
|
|
@ -4,6 +4,7 @@ import Label from '@components/forms/Label'
|
|||
import MultiSelectDropdown from '@components/forms/MultiSelectDropdown'
|
||||
import { EXPLORERS } from '@components/settings/PreferredExplorerSettings'
|
||||
import Button, { IconButton } from '@components/shared/Button'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import { Disclosure } from '@headlessui/react'
|
||||
import {
|
||||
|
@ -22,7 +23,6 @@ import { useTranslation } from 'next-i18next'
|
|||
import Image from 'next/legacy/image'
|
||||
import { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { PREFERRED_EXPLORER_KEY } from 'utils/constants'
|
||||
import { formatDecimal, formatFixedDecimals } from 'utils/numbers'
|
||||
import ActivityFeedTable from './ActivityFeedTable'
|
||||
|
||||
interface AdvancedFilters {
|
||||
|
@ -428,25 +428,25 @@ const ActivityDetails = ({
|
|||
<div className="col-span-1">
|
||||
<p className="mb-0.5 text-sm">{t('activity:asset-liquidated')}</p>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
{formatDecimal(asset_amount)}{' '}
|
||||
<FormatNumericValue value={asset_amount} />{' '}
|
||||
<span className="font-body">{asset_symbol}</span>
|
||||
<span className="ml-2 font-body text-th-fgd-3">at</span>{' '}
|
||||
{formatFixedDecimals(asset_price, true)}
|
||||
<FormatNumericValue value={asset_price} isUsd />
|
||||
</p>
|
||||
<p className="font-mono text-xs text-th-fgd-3">
|
||||
{formatFixedDecimals(asset_price * asset_amount, true)}
|
||||
<FormatNumericValue value={asset_price * asset_amount} isUsd />
|
||||
</p>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="mb-0.5 text-sm">{t('activity:asset-returned')}</p>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
{formatDecimal(liab_amount)}{' '}
|
||||
<FormatNumericValue value={liab_amount} />{' '}
|
||||
<span className="font-body">{liab_symbol}</span>
|
||||
<span className="ml-2 font-body text-th-fgd-3">at</span>{' '}
|
||||
{formatFixedDecimals(liab_price, true)}
|
||||
<FormatNumericValue value={liab_price} isUsd />
|
||||
</p>
|
||||
<p className="font-mono text-xs text-th-fgd-3">
|
||||
{formatFixedDecimals(liab_price * liab_amount, true)}
|
||||
<FormatNumericValue value={liab_price * liab_amount} isUsd />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { EXPLORERS } from '@components/settings/PreferredExplorerSettings'
|
||||
import { IconButton, LinkButton } from '@components/shared/Button'
|
||||
import ConnectEmptyState from '@components/shared/ConnectEmptyState'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import SheenLoader from '@components/shared/SheenLoader'
|
||||
import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
|
@ -20,7 +21,7 @@ import { useTranslation } from 'next-i18next'
|
|||
import Image from 'next/legacy/image'
|
||||
import { Fragment, useCallback, useState } from 'react'
|
||||
import { PAGINATION_PAGE_LENGTH, PREFERRED_EXPLORER_KEY } from 'utils/constants'
|
||||
import { formatDecimal, formatFixedDecimals } from 'utils/numbers'
|
||||
import { formatNumericValue } from 'utils/numbers'
|
||||
import { breakpoints } from 'utils/theme'
|
||||
|
||||
const formatFee = (value: number) => {
|
||||
|
@ -74,25 +75,28 @@ const ActivityFeedTable = ({
|
|||
const { side, liab_amount, liab_symbol, asset_amount, asset_symbol } =
|
||||
activity.activity_details
|
||||
if (side === 'liqee') {
|
||||
credit = { value: formatDecimal(liab_amount), symbol: liab_symbol }
|
||||
credit = { value: formatNumericValue(liab_amount), symbol: liab_symbol }
|
||||
debit = {
|
||||
value: formatDecimal(asset_amount),
|
||||
value: formatNumericValue(asset_amount),
|
||||
symbol: asset_symbol,
|
||||
}
|
||||
} else {
|
||||
credit = { value: formatDecimal(asset_amount), symbol: asset_symbol }
|
||||
debit = { value: formatDecimal(liab_amount), symbol: liab_symbol }
|
||||
credit = {
|
||||
value: formatNumericValue(asset_amount),
|
||||
symbol: asset_symbol,
|
||||
}
|
||||
debit = { value: formatNumericValue(liab_amount), symbol: liab_symbol }
|
||||
}
|
||||
}
|
||||
if (activity_type === 'deposit') {
|
||||
const { symbol, quantity } = activity.activity_details
|
||||
credit = { value: formatDecimal(quantity), symbol }
|
||||
credit = { value: formatNumericValue(quantity), symbol }
|
||||
debit = { value: '0', symbol: '' }
|
||||
}
|
||||
if (activity_type === 'withdraw') {
|
||||
const { symbol, quantity } = activity.activity_details
|
||||
credit = { value: '0', symbol: '' }
|
||||
debit = { value: formatDecimal(quantity * -1), symbol }
|
||||
debit = { value: formatNumericValue(quantity * -1), symbol }
|
||||
}
|
||||
if (activity_type === 'swap') {
|
||||
const {
|
||||
|
@ -102,30 +106,36 @@ const ActivityFeedTable = ({
|
|||
swap_out_symbol,
|
||||
} = activity.activity_details
|
||||
credit = {
|
||||
value: formatDecimal(swap_out_amount),
|
||||
value: formatNumericValue(swap_out_amount),
|
||||
symbol: swap_out_symbol,
|
||||
}
|
||||
debit = {
|
||||
value: formatDecimal(swap_in_amount * -1),
|
||||
value: formatNumericValue(swap_in_amount * -1),
|
||||
symbol: swap_in_symbol,
|
||||
}
|
||||
}
|
||||
if (activity_type === 'perp_trade') {
|
||||
const { perp_market_name, price, quantity } = activity.activity_details
|
||||
credit = { value: quantity, symbol: perp_market_name }
|
||||
debit = { value: formatDecimal(quantity * price * -1), symbol: 'USDC' }
|
||||
debit = {
|
||||
value: formatNumericValue(quantity * price * -1),
|
||||
symbol: 'USDC',
|
||||
}
|
||||
}
|
||||
if (activity_type === 'openbook_trade') {
|
||||
const { side, price, size, base_symbol, quote_symbol } =
|
||||
activity.activity_details
|
||||
credit =
|
||||
side === 'buy'
|
||||
? { value: formatDecimal(size), symbol: base_symbol }
|
||||
: { value: formatDecimal(size * price), symbol: quote_symbol }
|
||||
? { value: formatNumericValue(size), symbol: base_symbol }
|
||||
: { value: formatNumericValue(size * price), symbol: quote_symbol }
|
||||
debit =
|
||||
side === 'buy'
|
||||
? { value: formatDecimal(size * price * -1), symbol: quote_symbol }
|
||||
: { value: formatDecimal(size * -1), symbol: base_symbol }
|
||||
? {
|
||||
value: formatNumericValue(size * price * -1),
|
||||
symbol: quote_symbol,
|
||||
}
|
||||
: { value: formatNumericValue(size * -1), symbol: base_symbol }
|
||||
}
|
||||
return { credit, debit }
|
||||
}
|
||||
|
@ -274,7 +284,7 @@ const ActivityFeedTable = ({
|
|||
!isOpenbook
|
||||
? '+'
|
||||
: ''}
|
||||
{formatFixedDecimals(value, true)}
|
||||
<FormatNumericValue value={value} isUsd />
|
||||
</Td>
|
||||
<Td>
|
||||
{activity_type !== 'liquidate_token_with_token' ? (
|
||||
|
@ -392,24 +402,24 @@ const MobileActivityFeedItem = ({
|
|||
</p>
|
||||
<p className="text-right font-mono text-sm text-th-fgd-1">
|
||||
{isLiquidation ? (
|
||||
formatFixedDecimals(value, true)
|
||||
<FormatNumericValue value={value} isUsd />
|
||||
) : isSwap ? (
|
||||
<>
|
||||
<span className="mr-1">
|
||||
{activity.activity_details.swap_in_amount.toLocaleString(
|
||||
undefined,
|
||||
{ maximumFractionDigits: 6 }
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={activity.activity_details.swap_in_amount}
|
||||
decimals={6}
|
||||
/>
|
||||
</span>
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{activity.activity_details.swap_in_symbol}
|
||||
</span>
|
||||
<span className="mx-1 font-body text-th-fgd-3">for</span>
|
||||
<span className="mr-1">
|
||||
{activity.activity_details.swap_out_amount.toLocaleString(
|
||||
undefined,
|
||||
{ maximumFractionDigits: 6 }
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={activity.activity_details.swap_out_amount}
|
||||
decimals={6}
|
||||
/>
|
||||
</span>
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{activity.activity_details.swap_out_symbol}
|
||||
|
@ -506,37 +516,51 @@ const MobileActivityFeedItem = ({
|
|||
<div className="col-span-1">
|
||||
<p className="mb-0.5 text-sm">{t('activity:asset-liquidated')}</p>
|
||||
<p className="font-mono text-sm text-th-fgd-1">
|
||||
{formatDecimal(activity.activity_details.asset_amount)}{' '}
|
||||
<FormatNumericValue
|
||||
value={activity.activity_details.asset_amount}
|
||||
/>{' '}
|
||||
<span className="font-body">
|
||||
{activity.activity_details.asset_symbol}
|
||||
</span>
|
||||
<span className="ml-2 font-body text-th-fgd-3">at</span>{' '}
|
||||
{formatFixedDecimals(activity.activity_details.asset_price, true)}
|
||||
<FormatNumericValue
|
||||
value={activity.activity_details.asset_price}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
<p className="font-mono text-xs text-th-fgd-3">
|
||||
{formatFixedDecimals(
|
||||
activity.activity_details.asset_price *
|
||||
activity.activity_details.asset_amount,
|
||||
true
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
activity.activity_details.asset_price *
|
||||
activity.activity_details.asset_amount
|
||||
}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="mb-0.5 text-sm">{t('activity:asset-returned')}</p>
|
||||
<p className="font-mono text-sm text-th-fgd-1">
|
||||
{formatDecimal(activity.activity_details.liab_amount)}{' '}
|
||||
<FormatNumericValue
|
||||
value={activity.activity_details.liab_amount}
|
||||
/>{' '}
|
||||
<span className="font-body">
|
||||
{activity.activity_details.liab_symbol}
|
||||
</span>
|
||||
<span className="ml-2 font-body text-th-fgd-3">at</span>{' '}
|
||||
{formatFixedDecimals(activity.activity_details.liab_price, true)}
|
||||
<FormatNumericValue
|
||||
value={activity.activity_details.liab_price}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
<p className="font-mono text-xs text-th-fgd-3">
|
||||
{formatFixedDecimals(
|
||||
activity.activity_details.liab_price *
|
||||
activity.activity_details.liab_amount,
|
||||
true
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
activity.activity_details.liab_price *
|
||||
activity.activity_details.liab_amount
|
||||
}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<div className="col-span-2 flex justify-center pt-3">
|
||||
|
|
|
@ -3,17 +3,30 @@ import {
|
|||
HealthType,
|
||||
toUiDecimalsForQuote,
|
||||
} from '@blockworks-foundation/mango-v4'
|
||||
import { formatFixedDecimals } from '../../utils/numbers'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { useMemo } from 'react'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
const SummaryItem = ({ label, value }: { label: string; value: string }) => {
|
||||
const SummaryItem = ({
|
||||
label,
|
||||
value,
|
||||
isUsd,
|
||||
suffix,
|
||||
}: {
|
||||
label: string
|
||||
value: number
|
||||
isUsd?: boolean
|
||||
suffix?: string
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<p className="text-sm text-th-fgd-3">{label}</p>
|
||||
<p className="font-mono text-sm text-th-fgd-1">{value}</p>
|
||||
<p className="font-mono text-sm text-th-fgd-1">
|
||||
<FormatNumericValue value={value} decimals={2} isUsd={isUsd} />
|
||||
{suffix}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -56,20 +69,11 @@ const MangoAccountSummary = () => {
|
|||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<SummaryItem
|
||||
label={t('account-value')}
|
||||
value={formatFixedDecimals(accountValue, true, true)}
|
||||
/>
|
||||
<SummaryItem label={t('health')} value={`${health}%`} />
|
||||
<SummaryItem
|
||||
label={t('free-collateral')}
|
||||
value={formatFixedDecimals(freeCollateral, true, true)}
|
||||
/>
|
||||
<SummaryItem label={t('leverage')} value={`${leverage.toFixed(2)}x`} />
|
||||
<SummaryItem
|
||||
label={t('pnl')}
|
||||
value={formatFixedDecimals(pnl, true, true)}
|
||||
/>
|
||||
<SummaryItem label={t('account-value')} value={accountValue} isUsd />
|
||||
<SummaryItem label={t('health')} value={health} suffix="%" />
|
||||
<SummaryItem label={t('free-collateral')} value={freeCollateral} isUsd />
|
||||
<SummaryItem label={t('leverage')} value={leverage} suffix="x" />
|
||||
<SummaryItem label={t('pnl')} value={pnl} isUsd />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
import { ExclamationCircleIcon, TrashIcon } from '@heroicons/react/20/solid'
|
||||
import useUnsettledPerpPositions from 'hooks/useUnsettledPerpPositions'
|
||||
import { getMultipleAccounts } from '@project-serum/anchor/dist/cjs/utils/rpc'
|
||||
import { formatFixedDecimals } from 'utils/numbers'
|
||||
import { formatCurrencyValue } from 'utils/numbers'
|
||||
|
||||
const CloseAccountModal = ({ isOpen, onClose }: ModalProps) => {
|
||||
const { t } = useTranslation(['close-account'])
|
||||
|
@ -135,14 +135,10 @@ const CloseAccountModal = ({ isOpen, onClose }: ModalProps) => {
|
|||
{t('withdraw-assets-worth', {
|
||||
value:
|
||||
mangoAccount && group
|
||||
? formatFixedDecimals(
|
||||
? formatCurrencyValue(
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount!
|
||||
.current!.getEquity(group)
|
||||
.toNumber()
|
||||
),
|
||||
false,
|
||||
true
|
||||
mangoAccount!.current!.getEquity(group)
|
||||
)
|
||||
)
|
||||
: 0,
|
||||
})}
|
||||
|
|
|
@ -8,7 +8,6 @@ import dayjs from 'dayjs'
|
|||
import Change from '@components/shared/Change'
|
||||
import SheenLoader from '@components/shared/SheenLoader'
|
||||
import { NoSymbolIcon } from '@heroicons/react/20/solid'
|
||||
import { formatDecimal } from 'utils/numbers'
|
||||
|
||||
interface PnlChange {
|
||||
time: string
|
||||
|
@ -110,10 +109,7 @@ const PnlHistoryModal = ({
|
|||
key={v.time + v.pnlChange}
|
||||
>
|
||||
<p>{dayjs(v.time).format('YYYY-MM-DD')}</p>
|
||||
<Change
|
||||
change={Number(formatDecimal(v.pnlChange, 2))}
|
||||
prefix="$"
|
||||
/>
|
||||
<Change change={v.pnlChange} prefix="$" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -25,11 +25,6 @@ import {
|
|||
} from 'react'
|
||||
import { ALPHA_DEPOSIT_LIMIT } from 'utils/constants'
|
||||
import { notify } from 'utils/notifications'
|
||||
import {
|
||||
floorToDecimal,
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
} from 'utils/numbers'
|
||||
import ActionTokenList from '../account/ActionTokenList'
|
||||
import ButtonGroup from '../forms/ButtonGroup'
|
||||
import Input from '../forms/Input'
|
||||
|
@ -48,6 +43,7 @@ import { useEnhancedWallet } from '../wallet/EnhancedWalletProvider'
|
|||
import Modal from '../shared/Modal'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
import { withValueLimit } from '@components/swap/SwapForm'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
const UserSetupModal = ({
|
||||
isOpen,
|
||||
|
@ -169,10 +165,7 @@ const UserSetupModal = ({
|
|||
key,
|
||||
value,
|
||||
tokenDecimals: walletBalance.maxDecimals,
|
||||
walletBalance: floorToDecimal(
|
||||
walletBalance.maxAmount,
|
||||
walletBalance.maxDecimals
|
||||
).toNumber(),
|
||||
walletBalance: walletBalance.maxAmount,
|
||||
walletBalanceValue: walletBalance.maxAmount * value?.[0].uiPrice,
|
||||
}
|
||||
})
|
||||
|
@ -213,14 +206,22 @@ const UserSetupModal = ({
|
|||
tokenMax.amount < Number(depositAmount) ||
|
||||
(depositToken === 'SOL' && maxSolDeposit <= 0)
|
||||
|
||||
const setMax = useCallback(() => {
|
||||
const max = new Decimal(tokenMax.amount).toDecimalPlaces(
|
||||
tokenMax.decimals,
|
||||
Decimal.ROUND_FLOOR
|
||||
)
|
||||
setDepositAmount(max.toString())
|
||||
setSizePercentage('100')
|
||||
}, [tokenMax])
|
||||
|
||||
const handleSizePercentage = useCallback(
|
||||
(percentage: string) => {
|
||||
setSizePercentage(percentage)
|
||||
let amount = new Decimal(tokenMax.amount).mul(percentage).div(100)
|
||||
if (percentage !== '100') {
|
||||
amount = floorToDecimal(amount, tokenMax.decimals)
|
||||
}
|
||||
|
||||
const amount = new Decimal(tokenMax.amount)
|
||||
.mul(percentage)
|
||||
.div(100)
|
||||
.toDecimalPlaces(tokenMax.decimals, Decimal.ROUND_FLOOR)
|
||||
setDepositAmount(amount.toString())
|
||||
},
|
||||
[tokenMax]
|
||||
|
@ -422,20 +423,10 @@ const UserSetupModal = ({
|
|||
<Label text={t('amount')} />
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
decimals={tokenMax.decimals}
|
||||
label="Max"
|
||||
onClick={() => {
|
||||
setDepositAmount(
|
||||
floorToDecimal(
|
||||
tokenMax.amount,
|
||||
tokenMax.decimals
|
||||
).toFixed()
|
||||
)
|
||||
setSizePercentage('100')
|
||||
}}
|
||||
value={floorToDecimal(
|
||||
tokenMax.amount,
|
||||
tokenMax.decimals
|
||||
).toFixed()}
|
||||
onClick={setMax}
|
||||
value={tokenMax.amount}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-6 grid grid-cols-2">
|
||||
|
@ -492,16 +483,19 @@ const UserSetupModal = ({
|
|||
<p className="font-mono text-th-fgd-2">
|
||||
{depositAmount ? (
|
||||
<>
|
||||
{formatDecimal(
|
||||
Number(depositAmount),
|
||||
depositBank.mintDecimals
|
||||
)}{' '}
|
||||
<FormatNumericValue
|
||||
value={depositAmount}
|
||||
decimals={depositBank.mintDecimals}
|
||||
/>{' '}
|
||||
<span className="text-xs text-th-fgd-3">
|
||||
(
|
||||
{formatFixedDecimals(
|
||||
depositBank.uiPrice * Number(depositAmount),
|
||||
true
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
depositBank.uiPrice * Number(depositAmount)
|
||||
}
|
||||
decimals={2}
|
||||
isUsd
|
||||
/>
|
||||
)
|
||||
</span>
|
||||
</>
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
import Decimal from 'decimal.js'
|
||||
import FormatNumericValue from './FormatNumericValue'
|
||||
|
||||
const AmountWithValue = ({
|
||||
amount,
|
||||
amountDecimals,
|
||||
value,
|
||||
stacked,
|
||||
}: {
|
||||
amount: Decimal | number | string
|
||||
value: string
|
||||
amountDecimals?: number
|
||||
value: number | string
|
||||
stacked?: boolean
|
||||
}) => {
|
||||
return (
|
||||
<p className={`font-mono text-th-fgd-2 ${stacked ? 'text-right' : ''}`}>
|
||||
<>
|
||||
{amount}{' '}
|
||||
<FormatNumericValue value={amount} decimals={amountDecimals} />{' '}
|
||||
<span className={`text-th-fgd-4 ${stacked ? 'block' : ''}`}>
|
||||
{value}
|
||||
<FormatNumericValue value={value} decimals={2} isUsd={true} />
|
||||
</span>
|
||||
</>
|
||||
</p>
|
||||
|
|
|
@ -10,10 +10,8 @@ import { useRouter } from 'next/router'
|
|||
import { useCallback, useMemo } from 'react'
|
||||
import {
|
||||
floorToDecimal,
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
formatNumericValue,
|
||||
getDecimalCount,
|
||||
trimDecimals,
|
||||
} from 'utils/numbers'
|
||||
import { breakpoints } from 'utils/theme'
|
||||
import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm'
|
||||
|
@ -25,6 +23,7 @@ import AmountWithValue from './AmountWithValue'
|
|||
import ConnectEmptyState from './ConnectEmptyState'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import Decimal from 'decimal.js'
|
||||
import FormatNumericValue from './FormatNumericValue'
|
||||
|
||||
const BalancesTable = () => {
|
||||
const { t } = useTranslation(['common', 'trade'])
|
||||
|
@ -109,41 +108,29 @@ const BalancesTable = () => {
|
|||
<Td className="text-right">
|
||||
<Balance bank={bank} />
|
||||
<p className="text-sm text-th-fgd-4">
|
||||
{mangoAccount
|
||||
? `${formatFixedDecimals(
|
||||
mangoAccount.getTokenBalanceUi(bank) * bank.uiPrice,
|
||||
true
|
||||
)}`
|
||||
: '$0.00'}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
mangoAccount
|
||||
? mangoAccount.getTokenBalanceUi(bank) * bank.uiPrice
|
||||
: 0
|
||||
}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</Td>
|
||||
<Td className="text-right">
|
||||
<AmountWithValue
|
||||
amount={
|
||||
inOrders
|
||||
? formatDecimal(Number(inOrders), bank.mintDecimals)
|
||||
: '0'
|
||||
}
|
||||
value={formatFixedDecimals(
|
||||
inOrders * bank.uiPrice,
|
||||
true,
|
||||
true
|
||||
)}
|
||||
amount={inOrders}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={inOrders * bank.uiPrice}
|
||||
stacked
|
||||
/>
|
||||
</Td>
|
||||
<Td className="text-right">
|
||||
<AmountWithValue
|
||||
amount={
|
||||
unsettled
|
||||
? formatDecimal(Number(unsettled), bank.mintDecimals)
|
||||
: '0'
|
||||
}
|
||||
value={formatFixedDecimals(
|
||||
unsettled * bank.uiPrice,
|
||||
true,
|
||||
true
|
||||
)}
|
||||
amount={unsettled}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={unsettled * bank.uiPrice}
|
||||
stacked
|
||||
/>
|
||||
</Td>
|
||||
|
@ -186,24 +173,33 @@ const BalancesTable = () => {
|
|||
<div className="mb-0.5 flex justify-end space-x-1.5">
|
||||
<Balance bank={bank} />
|
||||
<span className="text-sm text-th-fgd-4">
|
||||
{mangoAccount
|
||||
? `${formatFixedDecimals(
|
||||
mangoAccount.getTokenBalanceUi(bank) * bank.uiPrice,
|
||||
false,
|
||||
true
|
||||
)}`
|
||||
: '$0.00'}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
mangoAccount
|
||||
? mangoAccount.getTokenBalanceUi(bank) * bank.uiPrice
|
||||
: 0
|
||||
}
|
||||
isUsd
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
<p className="text-xs text-th-fgd-4">
|
||||
{t('trade:in-orders')}:{' '}
|
||||
<span className="font-mono text-th-fgd-3">{inOrders}</span>
|
||||
<span className="font-mono text-th-fgd-3">
|
||||
<FormatNumericValue
|
||||
value={inOrders}
|
||||
decimals={bank.mintDecimals}
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-xs text-th-fgd-4">
|
||||
{t('trade:unsettled')}:{' '}
|
||||
<span className="font-mono text-th-fgd-3">
|
||||
{unsettled ? unsettled.toFixed(bank.mintDecimals) : 0}
|
||||
<FormatNumericValue
|
||||
value={unsettled}
|
||||
decimals={bank.mintDecimals}
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -253,29 +249,32 @@ const Balance = ({ bank }: { bank: Bank }) => {
|
|||
}
|
||||
|
||||
let minOrderDecimals: number
|
||||
let tickSize: number
|
||||
let tickDecimals: number
|
||||
if (selectedMarket instanceof Serum3Market) {
|
||||
const market = group.getSerum3ExternalMarket(
|
||||
selectedMarket.serumMarketExternal
|
||||
)
|
||||
minOrderDecimals = getDecimalCount(market.minOrderSize)
|
||||
tickSize = getDecimalCount(market.tickSize)
|
||||
tickDecimals = getDecimalCount(market.tickSize)
|
||||
} else {
|
||||
minOrderDecimals = getDecimalCount(selectedMarket.minOrderSize)
|
||||
tickSize = getDecimalCount(selectedMarket.tickSize)
|
||||
tickDecimals = getDecimalCount(selectedMarket.tickSize)
|
||||
}
|
||||
|
||||
if (type === 'quote') {
|
||||
const trimmedBalance = trimDecimals(balance, tickSize)
|
||||
const baseSize = trimDecimals(trimmedBalance / price, minOrderDecimals)
|
||||
const quoteSize = trimDecimals(baseSize * price, tickSize)
|
||||
const floorBalance = floorToDecimal(balance, tickDecimals).toNumber()
|
||||
const baseSize = floorToDecimal(
|
||||
floorBalance / price,
|
||||
minOrderDecimals
|
||||
).toNumber()
|
||||
const quoteSize = floorToDecimal(baseSize * price, tickDecimals)
|
||||
set((s) => {
|
||||
s.tradeForm.baseSize = baseSize.toString()
|
||||
s.tradeForm.quoteSize = quoteSize.toString()
|
||||
})
|
||||
} else {
|
||||
const baseSize = trimDecimals(balance, minOrderDecimals)
|
||||
const quoteSize = trimDecimals(baseSize * price, tickSize)
|
||||
const baseSize = floorToDecimal(balance, minOrderDecimals).toNumber()
|
||||
const quoteSize = floorToDecimal(baseSize * price, tickDecimals)
|
||||
set((s) => {
|
||||
s.tradeForm.baseSize = baseSize.toString()
|
||||
s.tradeForm.quoteSize = quoteSize.toString()
|
||||
|
@ -333,21 +332,21 @@ const Balance = ({ bank }: { bank: Bank }) => {
|
|||
handleTradeFormBalanceClick(Math.abs(balance), isBaseOrQuote)
|
||||
}
|
||||
>
|
||||
{formatDecimal(balance, bank.mintDecimals)}
|
||||
<FormatNumericValue value={balance} decimals={bank.mintDecimals} />
|
||||
</LinkButton>
|
||||
) : asPath.includes('/swap') ? (
|
||||
<LinkButton
|
||||
className="font-normal underline-offset-4"
|
||||
onClick={() =>
|
||||
handleSwapFormBalanceClick(
|
||||
floorToDecimal(balance, bank.mintDecimals).toNumber()
|
||||
Number(formatNumericValue(balance, bank.mintDecimals))
|
||||
)
|
||||
}
|
||||
>
|
||||
{formatDecimal(balance, bank.mintDecimals)}
|
||||
<FormatNumericValue value={balance} decimals={bank.mintDecimals} />
|
||||
</LinkButton>
|
||||
) : (
|
||||
formatDecimal(balance, bank.mintDecimals)
|
||||
<FormatNumericValue value={balance} decimals={bank.mintDecimals} />
|
||||
)}
|
||||
</p>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { MinusSmallIcon } from '@heroicons/react/20/solid'
|
||||
import { formatDecimal } from 'utils/numbers'
|
||||
import { DownTriangle, UpTriangle } from './DirectionTriangles'
|
||||
import FormatNumericValue from './FormatNumericValue'
|
||||
|
||||
const Change = ({
|
||||
change,
|
||||
|
@ -42,7 +42,10 @@ const Change = ({
|
|||
}`}
|
||||
>
|
||||
{prefix ? prefix : ''}
|
||||
{isNaN(change) ? '0.00' : formatDecimal(Math.abs(change), 2)}
|
||||
<FormatNumericValue
|
||||
value={isNaN(change) ? '0.00' : Math.abs(change)}
|
||||
decimals={2}
|
||||
/>
|
||||
{suffix ? suffix : ''}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useMemo } from 'react'
|
||||
import { formatFixedDecimals } from 'utils/numbers'
|
||||
import FormatNumericValue from './FormatNumericValue'
|
||||
|
||||
interface DailyRangeProps {
|
||||
high: number
|
||||
|
@ -16,7 +16,7 @@ const DailyRange = ({ high, low, price }: DailyRangeProps) => {
|
|||
<div className="flex items-center justify-between md:block">
|
||||
<div className="flex items-center">
|
||||
<span className={`pr-2 font-mono text-th-fgd-2`}>
|
||||
{formatFixedDecimals(low, true)}
|
||||
<FormatNumericValue value={low} isUsd />
|
||||
</span>
|
||||
<div className="mt-[2px] flex h-2 w-32 rounded-sm bg-th-bkg-3">
|
||||
<div
|
||||
|
@ -27,7 +27,7 @@ const DailyRange = ({ high, low, price }: DailyRangeProps) => {
|
|||
></div>
|
||||
</div>
|
||||
<span className={`pl-2 font-mono text-th-fgd-2`}>
|
||||
{formatFixedDecimals(high, true)}
|
||||
<FormatNumericValue value={high} isUsd />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -21,10 +21,11 @@ import ChartRangeButtons from './ChartRangeButtons'
|
|||
import Change from './Change'
|
||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import { ANIMATION_SETTINGS_KEY } from 'utils/constants'
|
||||
import { formatFixedDecimals } from 'utils/numbers'
|
||||
import { formatNumericValue } from 'utils/numbers'
|
||||
import { INITIAL_ANIMATION_SETTINGS } from '@components/settings/AnimationSettings'
|
||||
import { AxisDomain } from 'recharts/types/util/types'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import FormatNumericValue from './FormatNumericValue'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
|
@ -155,17 +156,18 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
play
|
||||
numbers={`${
|
||||
mouseData[yKey] < 0 ? '-' : ''
|
||||
}${prefix}${formatFixedDecimals(
|
||||
}${prefix}${formatNumericValue(
|
||||
Math.abs(mouseData[yKey])
|
||||
)}${suffix}`}
|
||||
/>
|
||||
) : (
|
||||
<span>
|
||||
{`${
|
||||
mouseData[yKey] < 0 ? '-' : ''
|
||||
}${prefix}${formatFixedDecimals(
|
||||
Math.abs(mouseData[yKey])
|
||||
)}${suffix}`}
|
||||
{mouseData[yKey] < 0 ? '-' : ''}
|
||||
{prefix}
|
||||
<FormatNumericValue
|
||||
value={Math.abs(mouseData[yKey])}
|
||||
/>
|
||||
{suffix}
|
||||
</span>
|
||||
)}
|
||||
{!hideChange ? (
|
||||
|
@ -202,17 +204,18 @@ const DetailedAreaChart: FunctionComponent<DetailedAreaChartProps> = ({
|
|||
play
|
||||
numbers={`${
|
||||
data[data.length - 1][yKey] < 0 ? '-' : ''
|
||||
}${prefix}${formatFixedDecimals(
|
||||
}${prefix}${formatNumericValue(
|
||||
Math.abs(data[data.length - 1][yKey])
|
||||
)}${suffix}`}
|
||||
/>
|
||||
) : (
|
||||
<span>
|
||||
{`${
|
||||
data[data.length - 1][yKey] < 0 ? '-' : ''
|
||||
}${prefix}${formatFixedDecimals(
|
||||
Math.abs(data[data.length - 1][yKey])
|
||||
)}${suffix}`}
|
||||
{data[data.length - 1][yKey] < 0 ? '-' : ''}
|
||||
{prefix}
|
||||
<FormatNumericValue
|
||||
value={Math.abs(data[data.length - 1][yKey])}
|
||||
/>
|
||||
{suffix}
|
||||
</span>
|
||||
)}
|
||||
{!hideChange ? (
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import Decimal from 'decimal.js'
|
||||
import { formatCurrencyValue, formatNumericValue } from 'utils/numbers'
|
||||
|
||||
const FormatNumericValue = ({
|
||||
value,
|
||||
decimals,
|
||||
isUsd,
|
||||
roundUp,
|
||||
}: {
|
||||
value: Decimal | number | string
|
||||
decimals?: number
|
||||
isUsd?: boolean
|
||||
roundUp?: boolean
|
||||
}) => {
|
||||
return (
|
||||
<span>
|
||||
{isUsd
|
||||
? formatCurrencyValue(value, decimals)
|
||||
: formatNumericValue(value, decimals, roundUp)}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default FormatNumericValue
|
|
@ -1,17 +1,21 @@
|
|||
import Decimal from 'decimal.js'
|
||||
import { LinkButton } from './Button'
|
||||
import FormatNumericValue from './FormatNumericValue'
|
||||
|
||||
const MaxAmountButton = ({
|
||||
className,
|
||||
decimals,
|
||||
disabled,
|
||||
label,
|
||||
onClick,
|
||||
value,
|
||||
}: {
|
||||
className?: string
|
||||
decimals: number
|
||||
disabled?: boolean
|
||||
label: string
|
||||
onClick: () => void
|
||||
value: string
|
||||
value: number | string | Decimal
|
||||
}) => {
|
||||
return (
|
||||
<LinkButton
|
||||
|
@ -20,7 +24,9 @@ const MaxAmountButton = ({
|
|||
onClick={onClick}
|
||||
>
|
||||
<p className="mr-1 text-th-fgd-4">{label}:</p>
|
||||
<span className="font-mono text-th-fgd-2 underline">{value}</span>
|
||||
<span className="font-mono text-th-fgd-2 underline">
|
||||
<FormatNumericValue value={value} decimals={decimals} />
|
||||
</span>
|
||||
</LinkButton>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@ import mangoStore from '@store/mangoStore'
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useMemo } from 'react'
|
||||
import { formatFixedDecimals } from 'utils/numbers'
|
||||
import { formatYAxis } from 'utils/formatting'
|
||||
import { formatNumericValue } from 'utils/numbers'
|
||||
const DetailedAreaChart = dynamic(
|
||||
() => import('@components/shared/DetailedAreaChart'),
|
||||
{ ssr: false }
|
||||
|
@ -72,7 +73,7 @@ const PerpMarketDetails = ({
|
|||
daysToShow={'999'}
|
||||
heightClass="h-64"
|
||||
prefix="$"
|
||||
tickFormat={(x) => formatFixedDecimals(x, true)}
|
||||
tickFormat={(x) => formatYAxis(x)}
|
||||
title={t('price')}
|
||||
xKey="date_hour"
|
||||
yKey={'price'}
|
||||
|
@ -95,7 +96,7 @@ const PerpMarketDetails = ({
|
|||
daysToShow={'999'}
|
||||
heightClass="h-64"
|
||||
suffix="%"
|
||||
tickFormat={(x) => formatFixedDecimals(x)}
|
||||
tickFormat={(x) => formatNumericValue(x)}
|
||||
title={t('hourly-funding')}
|
||||
xKey="date_hour"
|
||||
yKey={'funding_rate_hourly'}
|
||||
|
@ -107,7 +108,7 @@ const PerpMarketDetails = ({
|
|||
daysToShow={'999'}
|
||||
heightClass="h-64"
|
||||
suffix="%"
|
||||
tickFormat={(x) => formatFixedDecimals(x)}
|
||||
tickFormat={(x) => formatNumericValue(x)}
|
||||
title={t('instantaneous-funding')}
|
||||
xKey="date_hour"
|
||||
yKey={'instantaneous_funding_rate'}
|
||||
|
|
|
@ -4,7 +4,6 @@ import { useTheme } from 'next-themes'
|
|||
import { useViewport } from '../../hooks/useViewport'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { COLORS } from '../../styles/colors'
|
||||
import { formatFixedDecimals } from '../../utils/numbers'
|
||||
import { breakpoints } from '../../utils/theme'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
import Change from '../shared/Change'
|
||||
|
@ -15,6 +14,7 @@ import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
|
|||
import { usePerpFundingRate } from '@components/trade/PerpFundingRate'
|
||||
import { IconButton } from '@components/shared/Button'
|
||||
import { ChevronRightIcon } from '@heroicons/react/20/solid'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
const SimpleAreaChart = dynamic(
|
||||
() => import('@components/shared/SimpleAreaChart'),
|
||||
{ ssr: false }
|
||||
|
@ -86,7 +86,9 @@ const PerpMarketsTable = ({
|
|||
</Td>
|
||||
<Td>
|
||||
<div className="flex flex-col text-right">
|
||||
<p>{formatFixedDecimals(market.uiPrice, true)}</p>
|
||||
<p>
|
||||
<FormatNumericValue value={market.uiPrice} isUsd />
|
||||
</p>
|
||||
</div>
|
||||
</Td>
|
||||
<Td>
|
||||
|
@ -126,10 +128,12 @@ const PerpMarketsTable = ({
|
|||
</span>
|
||||
</p>
|
||||
<p className="text-xs text-th-fgd-4">
|
||||
{formatFixedDecimals(
|
||||
market.openInterest.toNumber() * market.uiPrice,
|
||||
true
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
market.openInterest.toNumber() * market.uiPrice
|
||||
}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</Td>
|
||||
|
@ -213,7 +217,7 @@ const MobilePerpMarketItem = ({ market }: { market: PerpMarket }) => {
|
|||
<p className="text-th-fgd-1">{market.name}</p>
|
||||
<div className="flex items-center space-x-3">
|
||||
<p className="font-mono">
|
||||
{formatFixedDecimals(market.uiPrice, true)}
|
||||
<FormatNumericValue value={market.uiPrice} isUsd />
|
||||
</p>
|
||||
<Change change={change} suffix="%" />
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,6 @@ import { useMemo } from 'react'
|
|||
import { useViewport } from '../../hooks/useViewport'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { COLORS } from '../../styles/colors'
|
||||
import { formatFixedDecimals } from '../../utils/numbers'
|
||||
import { breakpoints } from '../../utils/theme'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
import Change from '../shared/Change'
|
||||
|
@ -14,6 +13,7 @@ import dynamic from 'next/dynamic'
|
|||
import { useCoingecko } from 'hooks/useCoingecko'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
const SimpleAreaChart = dynamic(
|
||||
() => import('@components/shared/SimpleAreaChart'),
|
||||
{ ssr: false }
|
||||
|
@ -72,9 +72,11 @@ const SpotMarketsTable = () => {
|
|||
<Td>
|
||||
<div className="flex flex-col text-right">
|
||||
<p>
|
||||
{oraclePrice
|
||||
? formatFixedDecimals(oraclePrice, true)
|
||||
: '–'}
|
||||
{oraclePrice ? (
|
||||
<FormatNumericValue value={oraclePrice} isUsd />
|
||||
) : (
|
||||
'–'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</Td>
|
||||
|
@ -174,7 +176,11 @@ const MobileSpotMarketItem = ({ market }: { market: Serum3Market }) => {
|
|||
<p className="text-th-fgd-1">{market.name}</p>
|
||||
<div className="flex items-center space-x-3">
|
||||
<p className="font-mono">
|
||||
{bank?.uiPrice ? formatFixedDecimals(bank.uiPrice, true) : '-'}
|
||||
{bank?.uiPrice ? (
|
||||
<FormatNumericValue value={bank.uiPrice} isUsd />
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</p>
|
||||
<Change change={change} suffix="%" />
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,6 @@ import { useTranslation } from 'next-i18next'
|
|||
import Image from 'next/legacy/image'
|
||||
import { Fragment, useEffect, useMemo, useState } from 'react'
|
||||
import { useViewport } from '../../hooks/useViewport'
|
||||
import { formatDecimal, formatFixedDecimals } from '../../utils/numbers'
|
||||
import { breakpoints } from '../../utils/theme'
|
||||
import { IconButton, LinkButton } from '../shared/Button'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
|
@ -20,6 +19,7 @@ import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
|
|||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import AmountWithValue from '@components/shared/AmountWithValue'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
const TokenStats = () => {
|
||||
const { t } = useTranslation(['common', 'token'])
|
||||
|
@ -96,11 +96,12 @@ const TokenStats = () => {
|
|||
</Tooltip>
|
||||
</div>
|
||||
</Th>
|
||||
<Th />
|
||||
</TrHead>
|
||||
</thead>
|
||||
<tbody>
|
||||
{banks.map(({ key, value }) => {
|
||||
const bank = value[0]
|
||||
const bank: Bank = value[0]
|
||||
|
||||
let logoURI
|
||||
if (mangoTokens?.length) {
|
||||
|
@ -130,45 +131,47 @@ const TokenStats = () => {
|
|||
</Td>
|
||||
<Td>
|
||||
<div className="flex flex-col text-right">
|
||||
<p>{formatFixedDecimals(deposits)}</p>
|
||||
<p className="text-th-fgd-4">
|
||||
{formatFixedDecimals(deposits * price, true, true)}
|
||||
</p>
|
||||
<AmountWithValue
|
||||
amount={deposits.toFixed(4)}
|
||||
value={(deposits * price).toFixed(2)}
|
||||
stacked
|
||||
/>
|
||||
</div>
|
||||
</Td>
|
||||
<Td>
|
||||
<div className="flex flex-col text-right">
|
||||
<p>{formatFixedDecimals(borrows)}</p>
|
||||
<p className="text-th-fgd-4">
|
||||
{formatFixedDecimals(borrows * price, true, true)}
|
||||
</p>
|
||||
<AmountWithValue
|
||||
amount={borrows.toFixed(4)}
|
||||
value={(borrows * price).toFixed(2)}
|
||||
stacked
|
||||
/>
|
||||
</div>
|
||||
</Td>
|
||||
<Td>
|
||||
<div className="flex flex-col text-right">
|
||||
<p>
|
||||
{available > 0 ? formatFixedDecimals(available) : '0'}
|
||||
</p>
|
||||
<p className="text-th-fgd-4">
|
||||
{available > 0
|
||||
? formatFixedDecimals(available * price, false, true)
|
||||
: '$0.00'}
|
||||
</p>
|
||||
<AmountWithValue
|
||||
amount={available}
|
||||
amountDecimals={bank.mintDecimals}
|
||||
value={(available * price).toFixed(2)}
|
||||
stacked
|
||||
/>
|
||||
</div>
|
||||
</Td>
|
||||
<Td>
|
||||
<div className="flex justify-end space-x-1.5">
|
||||
<p className="text-th-up">
|
||||
{formatDecimal(bank.getDepositRateUi(), 2, {
|
||||
fixed: true,
|
||||
})}
|
||||
<FormatNumericValue
|
||||
value={bank.getDepositRateUi()}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</p>
|
||||
<span className="text-th-fgd-4">|</span>
|
||||
<p className="text-th-down">
|
||||
{formatDecimal(bank.getBorrowRateUi(), 2, {
|
||||
fixed: true,
|
||||
})}
|
||||
<FormatNumericValue
|
||||
value={bank.getBorrowRateUi()}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</p>
|
||||
</div>
|
||||
|
@ -177,11 +180,10 @@ const TokenStats = () => {
|
|||
<div className="flex flex-col text-right">
|
||||
<p>
|
||||
{bank.uiDeposits() > 0
|
||||
? formatDecimal(
|
||||
(bank.uiBorrows() / bank.uiDeposits()) * 100,
|
||||
1,
|
||||
{ fixed: true }
|
||||
)
|
||||
? (
|
||||
(bank.uiBorrows() / bank.uiDeposits()) *
|
||||
100
|
||||
).toFixed(1)
|
||||
: '0.0'}
|
||||
%
|
||||
</p>
|
||||
|
@ -243,12 +245,8 @@ const TokenStats = () => {
|
|||
{t('total-deposits')}
|
||||
</p>
|
||||
<AmountWithValue
|
||||
amount={formatFixedDecimals(deposits)}
|
||||
value={formatFixedDecimals(
|
||||
deposits * price,
|
||||
true,
|
||||
true
|
||||
)}
|
||||
amount={deposits.toFixed(4)}
|
||||
value={(deposits * price).toFixed(2)}
|
||||
stacked
|
||||
/>
|
||||
</div>
|
||||
|
@ -257,8 +255,8 @@ const TokenStats = () => {
|
|||
{t('total-borrows')}
|
||||
</p>
|
||||
<AmountWithValue
|
||||
amount={formatFixedDecimals(borrows)}
|
||||
value={formatFixedDecimals(borrows * price, true, true)}
|
||||
amount={borrows.toFixed(4)}
|
||||
value={(borrows * price).toFixed(2)}
|
||||
stacked
|
||||
/>
|
||||
</div>
|
||||
|
@ -292,11 +290,19 @@ const TokenStats = () => {
|
|||
<p className="text-xs text-th-fgd-3">{t('rates')}</p>
|
||||
<p className="space-x-2">
|
||||
<span className="font-mono text-th-up">
|
||||
{formatDecimal(bank.getDepositRate().toNumber(), 2)}%
|
||||
<FormatNumericValue
|
||||
value={bank.getDepositRateUi()}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
<span className="font-normal text-th-fgd-4">|</span>
|
||||
<span className="font-mono text-th-down">
|
||||
{formatDecimal(bank.getBorrowRate().toNumber(), 2)}%
|
||||
<FormatNumericValue
|
||||
value={bank.getBorrowRateUi()}
|
||||
decimals={2}
|
||||
/>
|
||||
%
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -306,11 +312,10 @@ const TokenStats = () => {
|
|||
</p>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
{bank.uiDeposits() > 0
|
||||
? formatDecimal(
|
||||
(bank.uiBorrows() / bank.uiDeposits()) * 100,
|
||||
1,
|
||||
{ fixed: true }
|
||||
)
|
||||
? (
|
||||
(bank.uiBorrows() / bank.uiDeposits()) *
|
||||
100
|
||||
).toFixed(1)
|
||||
: '0.0'}
|
||||
%
|
||||
</p>
|
||||
|
@ -322,17 +327,15 @@ const TokenStats = () => {
|
|||
</p>
|
||||
</Tooltip>
|
||||
<p className="text-th-fgd-1">
|
||||
{available > 0 ? formatFixedDecimals(available) : '0'}{' '}
|
||||
<FormatNumericValue
|
||||
value={available}
|
||||
decimals={bank.mintDecimals}
|
||||
/>{' '}
|
||||
<span className="text-th-fgd-4">
|
||||
(
|
||||
{available > 0
|
||||
? formatFixedDecimals(
|
||||
available * price,
|
||||
false,
|
||||
true
|
||||
)
|
||||
: '$0.00'}
|
||||
)
|
||||
<FormatNumericValue
|
||||
value={(available * price).toFixed(2)}
|
||||
isUsd
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import Decimal from 'decimal.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
import { formatNumericValue } from 'utils/numbers'
|
||||
import { useTokenMax } from './useTokenMax'
|
||||
|
||||
const MaxSwapAmount = ({
|
||||
|
@ -21,29 +22,26 @@ const MaxSwapAmount = ({
|
|||
|
||||
if (mangoAccountLoading) return null
|
||||
|
||||
const maxBalanceValue = floorToDecimal(
|
||||
tokenMax.toNumber(),
|
||||
decimals
|
||||
).toFixed()
|
||||
const maxBorrowValue = floorToDecimal(
|
||||
amountWithBorrow.toNumber(),
|
||||
decimals
|
||||
).toFixed()
|
||||
const setMax = (value: Decimal) => {
|
||||
setAmountIn(formatNumericValue(value, decimals))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap justify-end pl-6 text-xs">
|
||||
<MaxAmountButton
|
||||
className="mb-0.5"
|
||||
decimals={decimals}
|
||||
label="Bal"
|
||||
onClick={() => setAmountIn(maxBalanceValue)}
|
||||
value={maxBalanceValue}
|
||||
onClick={() => setMax(tokenMax)}
|
||||
value={tokenMax}
|
||||
/>
|
||||
{useMargin ? (
|
||||
<MaxAmountButton
|
||||
className="mb-0.5 ml-2"
|
||||
decimals={decimals}
|
||||
label={t('max')}
|
||||
onClick={() => setAmountIn(maxBorrowValue)}
|
||||
value={maxBorrowValue}
|
||||
onClick={() => setMax(amountWithBorrow)}
|
||||
value={amountWithBorrow}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Dispatch, SetStateAction } from 'react'
|
||||
|
||||
import { RouteInfo, Token } from '../../types/jupiter'
|
||||
import { formatDecimal } from '../../utils/numbers'
|
||||
import Modal from '../shared/Modal'
|
||||
import useJupiterMints from '../../hooks/useJupiterMints'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
type RoutesModalProps = {
|
||||
onClose: () => void
|
||||
|
@ -92,10 +92,12 @@ const RoutesModal = ({
|
|||
</div>
|
||||
</div>
|
||||
<div className="text-lg">
|
||||
{formatDecimal(
|
||||
route.outAmount / 10 ** (outputTokenInfo?.decimals || 1),
|
||||
6
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
route.outAmount / 10 ** (outputTokenInfo?.decimals || 1)
|
||||
}
|
||||
decimals={outputTokenInfo?.decimals || 6}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
@ -10,7 +10,7 @@ import useMangoAccount from 'hooks/useMangoAccount'
|
|||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import { formatDecimal } from 'utils/numbers'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
// const generateSearchTerm = (item: Token, searchValue: string) => {
|
||||
// const normalizedSearchValue = searchValue.toLowerCase()
|
||||
|
@ -75,9 +75,17 @@ const TokenItem = ({
|
|||
token.amountWithBorrow &&
|
||||
token.decimals ? (
|
||||
<p className="font-mono text-sm text-th-fgd-2">
|
||||
{useMargin
|
||||
? formatDecimal(token.amountWithBorrow.toNumber(), token.decimals)
|
||||
: formatDecimal(token.amount.toNumber(), token.decimals)}
|
||||
{useMargin ? (
|
||||
<FormatNumericValue
|
||||
value={token.amountWithBorrow}
|
||||
decimals={token.decimals}
|
||||
/>
|
||||
) : (
|
||||
<FormatNumericValue
|
||||
value={token.amount}
|
||||
decimals={token.decimals}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
) : null}
|
||||
</button>
|
||||
|
|
|
@ -13,12 +13,7 @@ import { IconButton, LinkButton } from '../shared/Button'
|
|||
import { Transition } from '@headlessui/react'
|
||||
import SheenLoader from '../shared/SheenLoader'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import {
|
||||
countLeadingZeros,
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
trimDecimals,
|
||||
} from '../../utils/numbers'
|
||||
import { countLeadingZeros, floorToDecimal } from '../../utils/numbers'
|
||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import { PAGINATION_PAGE_LENGTH, PREFERRED_EXPLORER_KEY } from 'utils/constants'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
|
@ -29,6 +24,7 @@ import { EXPLORERS } from '@components/settings/PreferredExplorerSettings'
|
|||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import ConnectEmptyState from '@components/shared/ConnectEmptyState'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
const SwapHistoryTable = () => {
|
||||
const { t } = useTranslation(['common', 'settings', 'swap'])
|
||||
|
@ -104,7 +100,7 @@ const SwapHistoryTable = () => {
|
|||
} = h
|
||||
const borrowAmount =
|
||||
loan > 0
|
||||
? `${trimDecimals(loan, countLeadingZeros(loan) + 2)}`
|
||||
? `${floorToDecimal(loan, countLeadingZeros(loan) + 2)}`
|
||||
: 0
|
||||
const borrowFee =
|
||||
swap_in_loan_origination_fee > 0
|
||||
|
@ -152,8 +148,11 @@ const SwapHistoryTable = () => {
|
|||
</div>
|
||||
<div>
|
||||
<p className="whitespace-nowrap">
|
||||
{`${formatDecimal(swap_in_amount, inDecimals)}`}
|
||||
<span className="ml-1 font-body text-th-fgd-3">
|
||||
<FormatNumericValue
|
||||
value={swap_in_amount}
|
||||
decimals={inDecimals}
|
||||
/>{' '}
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{inSymbol}
|
||||
</span>
|
||||
</p>
|
||||
|
@ -161,7 +160,7 @@ const SwapHistoryTable = () => {
|
|||
<span className="font-body text-th-fgd-4">
|
||||
{t('price')}:
|
||||
</span>{' '}
|
||||
{formatFixedDecimals(swap_in_price_usd, true)}
|
||||
<FormatNumericValue value={swap_in_price_usd} isUsd />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -178,25 +177,31 @@ const SwapHistoryTable = () => {
|
|||
</div>
|
||||
<div>
|
||||
<p className="whitespace-nowrap">
|
||||
{`${formatDecimal(swap_out_amount, outDecimals)}`}
|
||||
<span className="ml-1 font-body text-th-fgd-3">
|
||||
<FormatNumericValue
|
||||
value={swap_out_amount}
|
||||
decimals={outDecimals}
|
||||
/>{' '}
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{outSymbol}
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-xs text-th-fgd-4">
|
||||
<span className="font-body">{t('price')}:</span>{' '}
|
||||
{formatFixedDecimals(swap_out_price_usd, true)}
|
||||
<FormatNumericValue
|
||||
value={swap_out_price_usd}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Td>
|
||||
<Td>
|
||||
<p className="text-right">
|
||||
{formatFixedDecimals(
|
||||
swap_out_price_usd * swap_out_amount,
|
||||
false,
|
||||
true
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={swap_out_price_usd * swap_out_amount}
|
||||
decimals={2}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</Td>
|
||||
<Td>
|
||||
|
@ -268,7 +273,7 @@ const SwapHistoryTable = () => {
|
|||
|
||||
const borrowAmount =
|
||||
loan > 0
|
||||
? `${trimDecimals(loan, countLeadingZeros(loan) + 2)}`
|
||||
? `${floorToDecimal(loan, countLeadingZeros(loan) + 2)}`
|
||||
: 0
|
||||
const borrowFee =
|
||||
swap_in_loan_origination_fee > 0
|
||||
|
@ -310,7 +315,10 @@ const SwapHistoryTable = () => {
|
|||
</div>
|
||||
<div>
|
||||
<p className="whitespace-nowrap font-mono text-th-fgd-1">
|
||||
{formatDecimal(swap_in_amount, inDecimals)}{' '}
|
||||
<FormatNumericValue
|
||||
value={swap_in_amount}
|
||||
decimals={inDecimals}
|
||||
/>{' '}
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{inSymbol}
|
||||
</span>
|
||||
|
@ -319,7 +327,7 @@ const SwapHistoryTable = () => {
|
|||
<span className="font-body text-th-fgd-4">
|
||||
{t('price')}:
|
||||
</span>{' '}
|
||||
{formatFixedDecimals(swap_in_price_usd, true)}
|
||||
<FormatNumericValue value={swap_in_price_usd} isUsd />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -335,7 +343,10 @@ const SwapHistoryTable = () => {
|
|||
</div>
|
||||
<div>
|
||||
<p className="whitespace-nowrap font-mono text-th-fgd-1">
|
||||
{formatDecimal(swap_out_amount, outDecimals)}{' '}
|
||||
<FormatNumericValue
|
||||
value={swap_out_amount}
|
||||
decimals={outDecimals}
|
||||
/>{' '}
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{outSymbol}
|
||||
</span>
|
||||
|
@ -344,7 +355,10 @@ const SwapHistoryTable = () => {
|
|||
<span className="font-body text-th-fgd-4">
|
||||
{t('price')}:
|
||||
</span>{' '}
|
||||
{formatFixedDecimals(swap_out_price_usd, true)}
|
||||
<FormatNumericValue
|
||||
value={swap_out_price_usd}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
} from '@heroicons/react/20/solid'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Image from 'next/legacy/image'
|
||||
import { formatDecimal, formatFixedDecimals } from '../../utils/numbers'
|
||||
import { formatNumericValue } from '../../utils/numbers'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import useJupiterMints from '../../hooks/useJupiterMints'
|
||||
import { RouteInfo } from 'types/jupiter'
|
||||
|
@ -43,6 +43,7 @@ import { Disclosure } from '@headlessui/react'
|
|||
import RoutesModal from './RoutesModal'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { createAssociatedTokenAccountIdempotentInstruction } from '@blockworks-foundation/mango-v4'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
type JupiterRouteInfoProps = {
|
||||
amountIn: Decimal
|
||||
|
@ -372,14 +373,14 @@ const SwapReviewRouteInfo = ({
|
|||
</div>
|
||||
</div>
|
||||
<p className="mb-0.5 flex items-center text-center text-lg">
|
||||
<span className="mr-1 font-mono text-th-fgd-1">{`${formatFixedDecimals(
|
||||
amountIn.toNumber()
|
||||
)}`}</span>{' '}
|
||||
<span className="mr-1 font-mono text-th-fgd-1">
|
||||
<FormatNumericValue value={amountIn} />
|
||||
</span>{' '}
|
||||
{inputTokenInfo?.symbol}
|
||||
<ArrowRightIcon className="mx-2 h-5 w-5 text-th-fgd-4" />
|
||||
<span className="mr-1 font-mono text-th-fgd-1">{`${formatFixedDecimals(
|
||||
amountOut.toNumber()
|
||||
)}`}</span>{' '}
|
||||
<span className="mr-1 font-mono text-th-fgd-1">
|
||||
<FormatNumericValue value={amountOut} />
|
||||
</span>{' '}
|
||||
{`${outputTokenInfo?.symbol}`}
|
||||
</p>
|
||||
</div>
|
||||
|
@ -396,7 +397,7 @@ const SwapReviewRouteInfo = ({
|
|||
<span className="font-body text-th-fgd-3">
|
||||
{inputTokenInfo?.symbol} ≈{' '}
|
||||
</span>
|
||||
{formatFixedDecimals(amountOut.div(amountIn).toNumber())}{' '}
|
||||
<FormatNumericValue value={amountOut.div(amountIn)} />{' '}
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{outputTokenInfo?.symbol}
|
||||
</span>
|
||||
|
@ -407,7 +408,7 @@ const SwapReviewRouteInfo = ({
|
|||
<span className="font-body text-th-fgd-3">
|
||||
{outputTokenInfo?.symbol} ≈{' '}
|
||||
</span>
|
||||
{formatFixedDecimals(amountIn.div(amountOut).toNumber())}{' '}
|
||||
<FormatNumericValue value={amountIn.div(amountOut)} />{' '}
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{inputTokenInfo?.symbol}
|
||||
</span>
|
||||
|
@ -446,17 +447,22 @@ const SwapReviewRouteInfo = ({
|
|||
</p>
|
||||
{outputTokenInfo?.decimals && selectedRoute ? (
|
||||
<p className="text-right font-mono text-sm text-th-fgd-2">
|
||||
{selectedRoute.swapMode === 'ExactIn'
|
||||
? formatDecimal(
|
||||
{selectedRoute.swapMode === 'ExactIn' ? (
|
||||
<FormatNumericValue
|
||||
value={
|
||||
selectedRoute.otherAmountThreshold /
|
||||
10 ** outputTokenInfo.decimals || 1,
|
||||
outputTokenInfo.decimals
|
||||
)
|
||||
: formatDecimal(
|
||||
selectedRoute.outAmount /
|
||||
10 ** outputTokenInfo.decimals || 1,
|
||||
outputTokenInfo.decimals
|
||||
)}{' '}
|
||||
10 ** outputTokenInfo.decimals
|
||||
}
|
||||
decimals={outputTokenInfo.decimals}
|
||||
/>
|
||||
) : (
|
||||
<FormatNumericValue
|
||||
value={
|
||||
selectedRoute.outAmount / 10 ** outputTokenInfo.decimals
|
||||
}
|
||||
decimals={outputTokenInfo.decimals}
|
||||
/>
|
||||
)}{' '}
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{outputTokenInfo?.symbol}
|
||||
</span>
|
||||
|
@ -468,11 +474,13 @@ const SwapReviewRouteInfo = ({
|
|||
<p className="text-sm text-th-fgd-3">{t('swap:maximum-cost')}</p>
|
||||
{inputTokenInfo?.decimals && selectedRoute ? (
|
||||
<p className="text-right font-mono text-sm text-th-fgd-2">
|
||||
{formatDecimal(
|
||||
selectedRoute.otherAmountThreshold /
|
||||
10 ** inputTokenInfo.decimals || 1,
|
||||
inputTokenInfo.decimals
|
||||
)}{' '}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
selectedRoute.otherAmountThreshold /
|
||||
10 ** inputTokenInfo.decimals
|
||||
}
|
||||
decimals={inputTokenInfo.decimals}
|
||||
/>{' '}
|
||||
<span className="font-body text-th-fgd-3">
|
||||
{inputTokenInfo?.symbol}
|
||||
</span>
|
||||
|
@ -494,19 +502,21 @@ const SwapReviewRouteInfo = ({
|
|||
content={
|
||||
balance
|
||||
? t('swap:tooltip-borrow-balance', {
|
||||
balance: formatFixedDecimals(balance),
|
||||
borrowAmount: formatFixedDecimals(borrowAmount),
|
||||
balance: formatNumericValue(balance),
|
||||
borrowAmount: formatNumericValue(borrowAmount),
|
||||
token: inputTokenInfo?.symbol,
|
||||
rate: formatDecimal(inputBank!.getBorrowRateUi(), 2, {
|
||||
fixed: true,
|
||||
}),
|
||||
rate: formatNumericValue(
|
||||
inputBank!.getBorrowRateUi(),
|
||||
2
|
||||
),
|
||||
})
|
||||
: t('swap:tooltip-borrow-no-balance', {
|
||||
borrowAmount: formatFixedDecimals(borrowAmount),
|
||||
borrowAmount: formatNumericValue(borrowAmount),
|
||||
token: inputTokenInfo?.symbol,
|
||||
rate: formatDecimal(inputBank!.getBorrowRateUi(), 2, {
|
||||
fixed: true,
|
||||
}),
|
||||
rate: formatNumericValue(
|
||||
inputBank!.getBorrowRateUi(),
|
||||
2
|
||||
),
|
||||
})
|
||||
}
|
||||
delay={250}
|
||||
|
@ -516,7 +526,7 @@ const SwapReviewRouteInfo = ({
|
|||
</p>
|
||||
</Tooltip>
|
||||
<p className="text-right font-mono text-sm text-th-fgd-2">
|
||||
~{formatFixedDecimals(borrowAmount)}{' '}
|
||||
~<FormatNumericValue value={borrowAmount} />{' '}
|
||||
<span className="font-body">{inputTokenInfo?.symbol}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -595,15 +605,17 @@ const SwapReviewRouteInfo = ({
|
|||
</Tooltip>
|
||||
<p className="text-right font-mono text-sm text-th-fgd-2">
|
||||
~
|
||||
{formatFixedDecimals(
|
||||
amountIn
|
||||
.mul(inputBank!.loanOriginationFeeRate.toFixed())
|
||||
.toNumber()
|
||||
)}{' '}
|
||||
<FormatNumericValue
|
||||
value={amountIn.mul(
|
||||
inputBank!.loanOriginationFeeRate.toNumber()
|
||||
)}
|
||||
/>{' '}
|
||||
<span className="font-body">{inputBank!.name}</span> (
|
||||
{formatFixedDecimals(
|
||||
inputBank!.loanOriginationFeeRate.toNumber() * 100
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={
|
||||
inputBank!.loanOriginationFeeRate.toNumber() * 100
|
||||
}
|
||||
/>
|
||||
%)
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from 'recharts'
|
||||
import FlipNumbers from 'react-flip-numbers'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
import { formatFixedDecimals } from '../../utils/numbers'
|
||||
import { formatNumericValue } from '../../utils/numbers'
|
||||
import SheenLoader from '../shared/SheenLoader'
|
||||
import { COLORS } from '../../styles/colors'
|
||||
import { useTheme } from 'next-themes'
|
||||
|
@ -29,6 +29,7 @@ import { ANIMATION_SETTINGS_KEY } from 'utils/constants'
|
|||
import { INITIAL_ANIMATION_SETTINGS } from '@components/settings/AnimationSettings'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { ArrowsRightLeftIcon, NoSymbolIcon } from '@heroicons/react/20/solid'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
|
@ -78,7 +79,7 @@ const CustomizedLabel = ({
|
|||
textAnchor={x && y && x > width / 3 ? 'end' : 'start'}
|
||||
className="font-mono"
|
||||
>
|
||||
{formatFixedDecimals(value)}
|
||||
{formatNumericValue(value)}
|
||||
</Text>
|
||||
)
|
||||
} else return <div />
|
||||
|
@ -220,10 +221,10 @@ const SwapTokenChart = () => {
|
|||
height={48}
|
||||
width={35}
|
||||
play
|
||||
numbers={formatFixedDecimals(mouseData['price'])}
|
||||
numbers={formatNumericValue(mouseData['price'])}
|
||||
/>
|
||||
) : (
|
||||
<span>{formatFixedDecimals(mouseData['price'])}</span>
|
||||
<FormatNumericValue value={mouseData['price']} />
|
||||
)}
|
||||
<span
|
||||
className={`ml-0 mt-2 flex items-center text-sm md:ml-3 md:mt-0`}
|
||||
|
@ -243,16 +244,14 @@ const SwapTokenChart = () => {
|
|||
height={48}
|
||||
width={35}
|
||||
play
|
||||
numbers={formatFixedDecimals(
|
||||
numbers={formatNumericValue(
|
||||
chartData[chartData.length - 1]['price']
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<span>
|
||||
{formatFixedDecimals(
|
||||
chartData[chartData.length - 1]['price']
|
||||
)}
|
||||
</span>
|
||||
<FormatNumericValue
|
||||
value={chartData[chartData.length - 1]['price']}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={`ml-0 mt-2 flex items-center text-sm md:ml-3 md:mt-0`}
|
||||
|
|
|
@ -2,13 +2,13 @@ import { Bank } from '@blockworks-foundation/mango-v4'
|
|||
import BorrowRepayModal from '@components/modals/BorrowRepayModal'
|
||||
import DepositWithdrawModal from '@components/modals/DepositWithdrawModal'
|
||||
import Button from '@components/shared/Button'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { formatDecimal } from 'utils/numbers'
|
||||
|
||||
const ActionPanel = ({ bank }: { bank: Bank }) => {
|
||||
const { t } = useTranslation('common')
|
||||
|
@ -46,12 +46,14 @@ const ActionPanel = ({ bank }: { bank: Bank }) => {
|
|||
{bank.name} {t('balance')}:
|
||||
</p>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{mangoAccount
|
||||
? formatDecimal(
|
||||
mangoAccount.getTokenBalanceUi(bank),
|
||||
bank.mintDecimals
|
||||
)
|
||||
: 0}
|
||||
{mangoAccount ? (
|
||||
<FormatNumericValue
|
||||
value={mangoAccount.getTokenBalanceUi(bank)}
|
||||
decimals={bank.mintDecimals}
|
||||
/>
|
||||
) : (
|
||||
0
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Bank } from '@blockworks-foundation/mango-v4'
|
||||
import Change from '@components/shared/Change'
|
||||
import ChartRangeButtons from '@components/shared/ChartRangeButtons'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import { ArrowSmallUpIcon, NoSymbolIcon } from '@heroicons/react/20/solid'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
|
@ -9,7 +10,6 @@ import parse from 'html-react-parser'
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react'
|
||||
import { formatFixedDecimals } from 'utils/numbers'
|
||||
const PriceChart = dynamic(() => import('@components/token/PriceChart'), {
|
||||
ssr: false,
|
||||
})
|
||||
|
@ -174,7 +174,7 @@ const CoingeckoStats = ({
|
|||
<p>{t('token:market-cap')}</p>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{market_cap?.usd ? (
|
||||
formatFixedDecimals(market_cap.usd, true)
|
||||
<FormatNumericValue value={market_cap.usd} isUsd />
|
||||
) : (
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{t('unavailable')}
|
||||
|
@ -191,7 +191,7 @@ const CoingeckoStats = ({
|
|||
<p>{t('token:volume')}</p>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{total_volume?.usd ? (
|
||||
formatFixedDecimals(total_volume.usd, true)
|
||||
<FormatNumericValue value={total_volume.usd} isUsd />
|
||||
) : (
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{t('unavailable')}
|
||||
|
@ -205,7 +205,7 @@ const CoingeckoStats = ({
|
|||
<div className="flex items-center font-mono text-th-fgd-2">
|
||||
<span className="mr-2">
|
||||
{ath?.usd ? (
|
||||
formatFixedDecimals(ath.usd, true)
|
||||
<FormatNumericValue value={ath.usd} isUsd />
|
||||
) : (
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{t('unavailable')}
|
||||
|
@ -228,7 +228,7 @@ const CoingeckoStats = ({
|
|||
<div className="flex items-center font-mono text-th-fgd-2">
|
||||
<span className="mr-2">
|
||||
{atl?.usd ? (
|
||||
formatFixedDecimals(atl.usd, true)
|
||||
<FormatNumericValue value={atl.usd} isUsd />
|
||||
) : (
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{t('unavailable')}
|
||||
|
@ -250,7 +250,10 @@ const CoingeckoStats = ({
|
|||
<p>{t('token:fdv')}</p>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{fully_diluted_valuation?.usd ? (
|
||||
formatFixedDecimals(fully_diluted_valuation.usd, true)
|
||||
<FormatNumericValue
|
||||
value={fully_diluted_valuation.usd}
|
||||
isUsd
|
||||
/>
|
||||
) : (
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{t('unavailable')}
|
||||
|
@ -269,7 +272,7 @@ const CoingeckoStats = ({
|
|||
<p>{t('token:circulating-supply')}</p>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{circulating_supply ? (
|
||||
formatFixedDecimals(circulating_supply)
|
||||
<FormatNumericValue value={circulating_supply} />
|
||||
) : (
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{t('unavailable')}
|
||||
|
@ -285,7 +288,7 @@ const CoingeckoStats = ({
|
|||
<p>{t('token:total-supply')}</p>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{total_supply ? (
|
||||
formatFixedDecimals(total_supply)
|
||||
<FormatNumericValue value={total_supply} />
|
||||
) : (
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{t('unavailable')}
|
||||
|
@ -298,7 +301,7 @@ const CoingeckoStats = ({
|
|||
<p>{t('token:max-supply')}</p>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{max_supply ? (
|
||||
formatFixedDecimals(max_supply)
|
||||
<FormatNumericValue value={max_supply} />
|
||||
) : (
|
||||
<span className="font-body text-th-fgd-4">
|
||||
{t('unavailable')}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useTheme } from 'next-themes'
|
|||
import { useMemo } from 'react'
|
||||
import { Area, AreaChart, ResponsiveContainer, XAxis, YAxis } from 'recharts'
|
||||
import { COLORS } from 'styles/colors'
|
||||
import { formatFixedDecimals } from 'utils/numbers'
|
||||
import { formatYAxis } from 'utils/formatting'
|
||||
|
||||
const PriceChart = ({
|
||||
prices,
|
||||
|
@ -71,7 +71,7 @@ const PriceChart = ({
|
|||
fill: 'var(--fgd-4)',
|
||||
fontSize: 10,
|
||||
}}
|
||||
tickFormatter={(x) => formatFixedDecimals(x, true)}
|
||||
tickFormatter={(x) => formatYAxis(x)}
|
||||
tickLine={false}
|
||||
/>
|
||||
</AreaChart>
|
||||
|
|
|
@ -5,7 +5,7 @@ import Image from 'next/legacy/image'
|
|||
import { useRouter } from 'next/router'
|
||||
import { useMemo, useState } from 'react'
|
||||
import FlipNumbers from 'react-flip-numbers'
|
||||
import { formatDecimal, formatFixedDecimals } from 'utils/numbers'
|
||||
import { formatCurrencyValue } from 'utils/numbers'
|
||||
import Link from 'next/link'
|
||||
import SheenLoader from '@components/shared/SheenLoader'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
|
@ -18,6 +18,7 @@ import ActionPanel from './ActionPanel'
|
|||
import ChartTabs from './ChartTabs'
|
||||
import CoingeckoStats from './CoingeckoStats'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
const DEFAULT_COINGECKO_VALUES = {
|
||||
ath: 0,
|
||||
|
@ -126,10 +127,10 @@ const TokenPage = () => {
|
|||
play
|
||||
delay={0.05}
|
||||
duration={1}
|
||||
numbers={formatFixedDecimals(bank.uiPrice, true)}
|
||||
numbers={formatCurrencyValue(bank.uiPrice)}
|
||||
/>
|
||||
) : (
|
||||
<span>{formatFixedDecimals(bank.uiPrice, true)}</span>
|
||||
<FormatNumericValue value={bank.uiPrice} isUsd />
|
||||
)}
|
||||
</div>
|
||||
{coingeckoTokenInfo.data ? (
|
||||
|
@ -156,13 +157,14 @@ const TokenPage = () => {
|
|||
<p className="tooltip-underline mr-1">{t('utilization')}:</p>
|
||||
</Tooltip>
|
||||
<span className="font-mono text-th-fgd-2 no-underline">
|
||||
{bank.uiDeposits() > 0
|
||||
? formatDecimal(
|
||||
(bank.uiBorrows() / bank.uiDeposits()) * 100,
|
||||
1,
|
||||
{ fixed: true }
|
||||
)
|
||||
: '0.0'}
|
||||
{bank.uiDeposits() > 0 ? (
|
||||
<FormatNumericValue
|
||||
value={(bank.uiBorrows() / bank.uiDeposits()) * 100}
|
||||
decimals={1}
|
||||
/>
|
||||
) : (
|
||||
'0.0'
|
||||
)}
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ import useMangoAccount from 'hooks/useMangoAccount'
|
|||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
import { formatNumericValue } from 'utils/numbers'
|
||||
import { useSpotMarketMax } from './SpotSlider'
|
||||
|
||||
const MaxSizeButton = ({
|
||||
|
@ -57,33 +57,30 @@ const MaxSizeButton = ({
|
|||
const set = mangoStore.getState().set
|
||||
set((state) => {
|
||||
if (side === 'buy') {
|
||||
state.tradeForm.quoteSize = floorToDecimal(max, tickDecimals).toFixed()
|
||||
state.tradeForm.quoteSize = formatNumericValue(max, tickDecimals)
|
||||
if (tradeType === 'Market' || !price) {
|
||||
state.tradeForm.baseSize = floorToDecimal(
|
||||
state.tradeForm.baseSize = formatNumericValue(
|
||||
max / oraclePrice,
|
||||
minOrderDecimals
|
||||
).toFixed()
|
||||
)
|
||||
} else {
|
||||
state.tradeForm.baseSize = floorToDecimal(
|
||||
state.tradeForm.baseSize = formatNumericValue(
|
||||
max / parseFloat(price),
|
||||
minOrderDecimals
|
||||
).toFixed()
|
||||
)
|
||||
}
|
||||
} else {
|
||||
state.tradeForm.baseSize = floorToDecimal(
|
||||
max,
|
||||
minOrderDecimals
|
||||
).toFixed()
|
||||
state.tradeForm.baseSize = formatNumericValue(max, minOrderDecimals)
|
||||
if (tradeType === 'Market' || !price) {
|
||||
state.tradeForm.quoteSize = floorToDecimal(
|
||||
state.tradeForm.quoteSize = formatNumericValue(
|
||||
max * oraclePrice,
|
||||
minOrderDecimals
|
||||
).toFixed()
|
||||
)
|
||||
} else {
|
||||
state.tradeForm.quoteSize = floorToDecimal(
|
||||
state.tradeForm.quoteSize = formatNumericValue(
|
||||
max * parseFloat(price),
|
||||
minOrderDecimals
|
||||
).toFixed()
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -102,20 +99,11 @@ const MaxSizeButton = ({
|
|||
const max = selectedMarket instanceof Serum3Market ? spotMax : perpMax || 0
|
||||
const tradePrice = tradeType === 'Market' ? oraclePrice : Number(price)
|
||||
if (side === 'buy') {
|
||||
return floorToDecimal(max / tradePrice, minOrderDecimals).toFixed()
|
||||
return max / tradePrice
|
||||
} else {
|
||||
return floorToDecimal(max, minOrderDecimals).toFixed()
|
||||
return max
|
||||
}
|
||||
}, [
|
||||
perpMax,
|
||||
spotMax,
|
||||
selectedMarket,
|
||||
minOrderDecimals,
|
||||
tickDecimals,
|
||||
price,
|
||||
side,
|
||||
tradeType,
|
||||
])
|
||||
}, [perpMax, spotMax, selectedMarket, price, side, tradeType])
|
||||
|
||||
return (
|
||||
<div className="mb-2 mt-3 flex items-center justify-between">
|
||||
|
@ -123,6 +111,7 @@ const MaxSizeButton = ({
|
|||
<FadeInFadeOut show={!!price}>
|
||||
<MaxAmountButton
|
||||
className="text-xs"
|
||||
decimals={minOrderDecimals}
|
||||
label={t('max')}
|
||||
onClick={handleMax}
|
||||
value={maxAmount}
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
import Input from '@components/forms/Input'
|
||||
import { IconButton } from '@components/shared/Button'
|
||||
import ConnectEmptyState from '@components/shared/ConnectEmptyState'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import Loading from '@components/shared/Loading'
|
||||
import SideBadge from '@components/shared/SideBadge'
|
||||
import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
|
||||
|
@ -30,7 +31,7 @@ import { useViewport } from 'hooks/useViewport'
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import { ChangeEvent, useCallback, useState } from 'react'
|
||||
import { notify } from 'utils/notifications'
|
||||
import { formatFixedDecimals, getDecimalCount } from 'utils/numbers'
|
||||
import { getDecimalCount } from 'utils/numbers'
|
||||
import { breakpoints } from 'utils/theme'
|
||||
import TableMarketName from './TableMarketName'
|
||||
|
||||
|
@ -325,7 +326,11 @@ const OpenOrders = () => {
|
|||
</>
|
||||
)}
|
||||
<Td className="w-[16.67%] text-right">
|
||||
{formatFixedDecimals(o.size * o.price, true, true)}
|
||||
<FormatNumericValue
|
||||
value={o.size * o.price}
|
||||
decimals={2}
|
||||
isUsd
|
||||
/>
|
||||
</Td>
|
||||
<Td className="w-[16.67%]">
|
||||
<div className="flex justify-end space-x-2">
|
||||
|
|
|
@ -4,7 +4,7 @@ import mangoStore from '@store/mangoStore'
|
|||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { trimDecimals } from 'utils/numbers'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
|
||||
const PerpButtonGroup = ({
|
||||
minOrderDecimals,
|
||||
|
@ -50,28 +50,27 @@ const PerpButtonGroup = ({
|
|||
|
||||
set((s) => {
|
||||
if (s.tradeForm.side === 'buy') {
|
||||
s.tradeForm.quoteSize = trimDecimals(size, tickDecimals).toFixed(
|
||||
tickDecimals
|
||||
)
|
||||
s.tradeForm.quoteSize = floorToDecimal(size, tickDecimals).toString()
|
||||
|
||||
if (Number(s.tradeForm.price)) {
|
||||
s.tradeForm.baseSize = trimDecimals(
|
||||
s.tradeForm.baseSize = floorToDecimal(
|
||||
size / Number(s.tradeForm.price),
|
||||
minOrderDecimals
|
||||
).toFixed(minOrderDecimals)
|
||||
).toString()
|
||||
} else {
|
||||
s.tradeForm.baseSize = ''
|
||||
}
|
||||
} else if (s.tradeForm.side === 'sell') {
|
||||
s.tradeForm.baseSize = trimDecimals(size, minOrderDecimals).toFixed(
|
||||
s.tradeForm.baseSize = floorToDecimal(
|
||||
size,
|
||||
minOrderDecimals
|
||||
)
|
||||
).toString()
|
||||
|
||||
if (Number(s.tradeForm.price)) {
|
||||
s.tradeForm.quoteSize = trimDecimals(
|
||||
s.tradeForm.quoteSize = floorToDecimal(
|
||||
size * Number(s.tradeForm.price),
|
||||
tickDecimals
|
||||
).toFixed(tickDecimals)
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { PerpMarket, PerpPosition } from '@blockworks-foundation/mango-v4'
|
||||
import Button, { LinkButton } from '@components/shared/Button'
|
||||
import ConnectEmptyState from '@components/shared/ConnectEmptyState'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
|
||||
import { NoSymbolIcon } from '@heroicons/react/20/solid'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
|
@ -10,13 +11,7 @@ import useMangoGroup from 'hooks/useMangoGroup'
|
|||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useCallback, useState } from 'react'
|
||||
import {
|
||||
formatDecimal,
|
||||
formatFixedDecimals,
|
||||
getDecimalCount,
|
||||
numberFormat,
|
||||
trimDecimals,
|
||||
} from 'utils/numbers'
|
||||
import { floorToDecimal, getDecimalCount } from 'utils/numbers'
|
||||
import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm'
|
||||
import MarketCloseModal from './MarketCloseModal'
|
||||
import PerpSideBadge from './PerpSideBadge'
|
||||
|
@ -96,10 +91,10 @@ const PerpPositions = () => {
|
|||
position.marketIndex
|
||||
)
|
||||
const basePosition = position.getBasePositionUi(market)
|
||||
const trimmedBasePosition = trimDecimals(
|
||||
const floorBasePosition = floorToDecimal(
|
||||
basePosition,
|
||||
getDecimalCount(market.minOrderSize)
|
||||
)
|
||||
).toNumber()
|
||||
const isSelectedMarket =
|
||||
selectedMarket instanceof PerpMarket &&
|
||||
selectedMarket.perpMarketIndex === position.marketIndex
|
||||
|
@ -124,38 +119,46 @@ const PerpPositions = () => {
|
|||
<p className="flex justify-end">
|
||||
{isSelectedMarket ? (
|
||||
<LinkButton
|
||||
onClick={() => handlePositionClick(trimmedBasePosition)}
|
||||
onClick={() => handlePositionClick(floorBasePosition)}
|
||||
>
|
||||
{Math.abs(trimmedBasePosition)}
|
||||
<FormatNumericValue
|
||||
value={Math.abs(basePosition)}
|
||||
decimals={getDecimalCount(market.minOrderSize)}
|
||||
/>
|
||||
</LinkButton>
|
||||
) : (
|
||||
Math.abs(trimmedBasePosition)
|
||||
<FormatNumericValue
|
||||
value={Math.abs(basePosition)}
|
||||
decimals={getDecimalCount(market.minOrderSize)}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
</Td>
|
||||
<Td className="text-right font-mono">
|
||||
<div>
|
||||
$
|
||||
{Math.abs(trimmedBasePosition * market._uiPrice).toFixed(2)}
|
||||
</div>
|
||||
<FormatNumericValue
|
||||
value={floorBasePosition * market._uiPrice}
|
||||
decimals={2}
|
||||
isUsd
|
||||
/>
|
||||
</Td>
|
||||
<Td className="text-right font-mono">
|
||||
<div>
|
||||
$
|
||||
{numberFormat.format(
|
||||
position.getAverageEntryPriceUi(market)
|
||||
)}
|
||||
</div>
|
||||
<FormatNumericValue
|
||||
value={position.getAverageEntryPriceUi(market)}
|
||||
isUsd
|
||||
/>
|
||||
</Td>
|
||||
<Td className={`text-right font-mono`}>
|
||||
<div>{formatDecimal(unsettledPnl, market.baseDecimals)}</div>
|
||||
<FormatNumericValue
|
||||
value={unsettledPnl}
|
||||
decimals={market.baseDecimals}
|
||||
/>
|
||||
</Td>
|
||||
<Td
|
||||
className={`text-right font-mono ${
|
||||
cummulativePnl > 0 ? 'text-th-up' : 'text-th-down'
|
||||
}`}
|
||||
>
|
||||
<div>{formatFixedDecimals(cummulativePnl, true)}</div>
|
||||
<FormatNumericValue value={cummulativePnl} isUsd />
|
||||
</Td>
|
||||
<Td className={`text-right`}>
|
||||
<Button
|
||||
|
|
|
@ -4,7 +4,7 @@ import mangoStore from '@store/mangoStore'
|
|||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { trimDecimals } from 'utils/numbers'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
|
||||
const PerpSlider = ({
|
||||
minOrderDecimals,
|
||||
|
@ -61,20 +61,20 @@ const PerpSlider = ({
|
|||
if (s.tradeForm.side === 'buy') {
|
||||
s.tradeForm.quoteSize = val
|
||||
if (Number(price)) {
|
||||
s.tradeForm.baseSize = trimDecimals(
|
||||
s.tradeForm.baseSize = floorToDecimal(
|
||||
parseFloat(val) / price,
|
||||
minOrderDecimals
|
||||
).toFixed(minOrderDecimals)
|
||||
).toString()
|
||||
} else {
|
||||
s.tradeForm.baseSize = ''
|
||||
}
|
||||
} else if (s.tradeForm.side === 'sell') {
|
||||
s.tradeForm.baseSize = val
|
||||
if (Number(price)) {
|
||||
s.tradeForm.quoteSize = trimDecimals(
|
||||
s.tradeForm.quoteSize = floorToDecimal(
|
||||
parseFloat(val) * price,
|
||||
tickDecimals
|
||||
).toFixed(tickDecimals)
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import useInterval from '@components/shared/useInterval'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import { floorToDecimal, getDecimalCount } from 'utils/numbers'
|
||||
import Decimal from 'decimal.js'
|
||||
import { formatNumericValue, getDecimalCount } from 'utils/numbers'
|
||||
import { ChartTradeType } from 'types'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
|
@ -162,25 +161,21 @@ const RecentTrades = () => {
|
|||
const side =
|
||||
trade.side || (trade.takerSide === 0 ? 'bid' : 'ask')
|
||||
|
||||
// const price =
|
||||
// typeof trade.price === 'number'
|
||||
// ? trade.price
|
||||
// : trade.price.toNumber()
|
||||
const formattedPrice = market?.tickSize
|
||||
? floorToDecimal(
|
||||
trade.price,
|
||||
getDecimalCount(market.tickSize)
|
||||
)
|
||||
: new Decimal(trade?.price || 0)
|
||||
const formattedPrice =
|
||||
market?.tickSize && trade.price
|
||||
? formatNumericValue(
|
||||
trade.price,
|
||||
getDecimalCount(market.tickSize)
|
||||
)
|
||||
: trade?.price || 0
|
||||
|
||||
// const size = trade?.quantity?.toNumber() || trade?.size
|
||||
const formattedSize =
|
||||
market?.minOrderSize && trade.size
|
||||
? floorToDecimal(
|
||||
? formatNumericValue(
|
||||
trade.size,
|
||||
getDecimalCount(market.minOrderSize)
|
||||
)
|
||||
: new Decimal(trade.size || 0)
|
||||
: trade?.size || 0
|
||||
|
||||
return (
|
||||
<tr className="font-mono text-xs" key={i}>
|
||||
|
@ -191,10 +186,10 @@ const RecentTrades = () => {
|
|||
: 'text-th-down'
|
||||
}`}
|
||||
>
|
||||
{formattedPrice.toFixed()}
|
||||
{formattedPrice}
|
||||
</td>
|
||||
<td className="pb-1.5 text-right text-th-fgd-3">
|
||||
{formattedSize.toFixed()}
|
||||
{formattedSize}
|
||||
</td>
|
||||
<td className="pb-1.5 text-right text-th-fgd-4">
|
||||
{trade.time
|
||||
|
|
|
@ -3,7 +3,7 @@ import mangoStore from '@store/mangoStore'
|
|||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { trimDecimals } from 'utils/numbers'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
import { useSpotMarketMax } from './SpotSlider'
|
||||
|
||||
const SpotButtonGroup = ({
|
||||
|
@ -29,28 +29,24 @@ const SpotButtonGroup = ({
|
|||
|
||||
set((s) => {
|
||||
if (s.tradeForm.side === 'buy') {
|
||||
s.tradeForm.quoteSize = trimDecimals(size, tickDecimals).toFixed(
|
||||
tickDecimals
|
||||
)
|
||||
s.tradeForm.quoteSize = floorToDecimal(size, tickDecimals).toString()
|
||||
|
||||
if (Number(s.tradeForm.price)) {
|
||||
s.tradeForm.baseSize = trimDecimals(
|
||||
s.tradeForm.baseSize = floorToDecimal(
|
||||
size / Number(s.tradeForm.price),
|
||||
minOrderDecimals
|
||||
).toFixed(minOrderDecimals)
|
||||
).toString()
|
||||
} else {
|
||||
s.tradeForm.baseSize = ''
|
||||
}
|
||||
} else if (s.tradeForm.side === 'sell') {
|
||||
s.tradeForm.baseSize = trimDecimals(size, tickDecimals).toFixed(
|
||||
minOrderDecimals
|
||||
)
|
||||
s.tradeForm.baseSize = floorToDecimal(size, tickDecimals).toString()
|
||||
|
||||
if (Number(s.tradeForm.price)) {
|
||||
s.tradeForm.quoteSize = trimDecimals(
|
||||
s.tradeForm.quoteSize = floorToDecimal(
|
||||
size * Number(s.tradeForm.price),
|
||||
tickDecimals
|
||||
).toFixed(tickDecimals)
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -5,7 +5,7 @@ import useMangoAccount from 'hooks/useMangoAccount'
|
|||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { GenericMarket } from 'types'
|
||||
import { trimDecimals } from 'utils/numbers'
|
||||
import { floorToDecimal } from 'utils/numbers'
|
||||
|
||||
export const useSpotMarketMax = (
|
||||
mangoAccount: MangoAccount | undefined,
|
||||
|
@ -78,20 +78,20 @@ const SpotSlider = ({
|
|||
if (s.tradeForm.side === 'buy') {
|
||||
s.tradeForm.quoteSize = val
|
||||
if (Number(price)) {
|
||||
s.tradeForm.baseSize = trimDecimals(
|
||||
s.tradeForm.baseSize = floorToDecimal(
|
||||
parseFloat(val) / price,
|
||||
minOrderDecimals
|
||||
).toFixed(minOrderDecimals)
|
||||
).toString()
|
||||
} else {
|
||||
s.tradeForm.baseSize = ''
|
||||
}
|
||||
} else if (s.tradeForm.side === 'sell') {
|
||||
s.tradeForm.baseSize = val
|
||||
if (Number(price)) {
|
||||
s.tradeForm.quoteSize = trimDecimals(
|
||||
s.tradeForm.quoteSize = floorToDecimal(
|
||||
parseFloat(val) * price,
|
||||
tickDecimals
|
||||
).toFixed(tickDecimals)
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
} from '@blockworks-foundation/mango-v4'
|
||||
import { IconButton, LinkButton } from '@components/shared/Button'
|
||||
import ConnectEmptyState from '@components/shared/ConnectEmptyState'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import SheenLoader from '@components/shared/SheenLoader'
|
||||
import SideBadge from '@components/shared/SideBadge'
|
||||
import {
|
||||
|
@ -27,7 +28,6 @@ import { useViewport } from 'hooks/useViewport'
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { PAGINATION_PAGE_LENGTH } from 'utils/constants'
|
||||
import { formatDecimal, formatFixedDecimals } from 'utils/numbers'
|
||||
import { breakpoints } from 'utils/theme'
|
||||
import TableMarketName from './TableMarketName'
|
||||
|
||||
|
@ -268,14 +268,18 @@ const TradeHistory = () => {
|
|||
</Td>
|
||||
<Td className="text-right font-mono">{trade.size}</Td>
|
||||
<Td className="text-right font-mono">
|
||||
{formatDecimal(trade.price)}
|
||||
<FormatNumericValue value={trade.price} />
|
||||
</Td>
|
||||
<Td className="text-right font-mono">
|
||||
{formatFixedDecimals(trade.price * trade.size, true)}
|
||||
<FormatNumericValue
|
||||
value={trade.price * trade.size}
|
||||
decimals={2}
|
||||
isUsd
|
||||
/>
|
||||
</Td>
|
||||
<Td className="text-right">
|
||||
<span className="font-mono">
|
||||
{formatDecimal(trade.feeCost)}
|
||||
<FormatNumericValue value={trade.feeCost} />
|
||||
</span>
|
||||
<p className="font-body text-xs text-th-fgd-4">
|
||||
{trade.liquidity}
|
||||
|
@ -292,7 +296,7 @@ const TradeHistory = () => {
|
|||
)}
|
||||
</Td>
|
||||
<Td className="xl:!pl-0">
|
||||
{trade.market.name.includes('PERP') ? (
|
||||
{trade.market.name.includes('PERP') ? (
|
||||
<div className="flex justify-end">
|
||||
<Tooltip content="View Counterparty" delay={250}>
|
||||
<a
|
||||
|
@ -336,7 +340,7 @@ const TradeHistory = () => {
|
|||
</span>
|
||||
{' for '}
|
||||
<span className="font-mono text-th-fgd-2">
|
||||
{formatDecimal(trade.price)}
|
||||
<FormatNumericValue value={trade.price} />
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -354,11 +358,11 @@ const TradeHistory = () => {
|
|||
)}
|
||||
</span>
|
||||
<p className="font-mono text-th-fgd-2">
|
||||
{formatFixedDecimals(
|
||||
trade.price * trade.size,
|
||||
true,
|
||||
true
|
||||
)}
|
||||
<FormatNumericValue
|
||||
value={trade.price * trade.size}
|
||||
decimals={2}
|
||||
isUsd
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
{trade.market.name.includes('PERP') ? (
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
Serum3Market,
|
||||
toUiDecimalsForQuote,
|
||||
} from '@blockworks-foundation/mango-v4'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import HealthImpact from '@components/shared/HealthImpact'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
@ -12,7 +13,6 @@ import useMangoGroup from 'hooks/useMangoGroup'
|
|||
import useSelectedMarket from 'hooks/useSelectedMarket'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useMemo } from 'react'
|
||||
import { formatFixedDecimals } from 'utils/numbers'
|
||||
import Slippage from './Slippage'
|
||||
|
||||
const TradeSummary = ({
|
||||
|
@ -76,13 +76,17 @@ const TradeSummary = ({
|
|||
<div className="flex justify-between text-xs">
|
||||
<p>{t('trade:order-value')}</p>
|
||||
<p className="text-th-fgd-2">
|
||||
{tradeForm.price && tradeForm.baseSize
|
||||
? formatFixedDecimals(
|
||||
parseFloat(tradeForm.price) * parseFloat(tradeForm.baseSize),
|
||||
false,
|
||||
true
|
||||
)
|
||||
: '0.00'}
|
||||
{tradeForm.price && tradeForm.baseSize ? (
|
||||
<FormatNumericValue
|
||||
value={
|
||||
parseFloat(tradeForm.price) * parseFloat(tradeForm.baseSize)
|
||||
}
|
||||
decimals={2}
|
||||
isUsd
|
||||
/>
|
||||
) : (
|
||||
'0.00'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<HealthImpact maintProjectedHealth={maintProjectedHealth} small />
|
||||
|
@ -91,15 +95,17 @@ const TradeSummary = ({
|
|||
<p className="tooltip-underline">{t('free-collateral')}</p>
|
||||
</Tooltip>
|
||||
<p className="text-th-fgd-2">
|
||||
{group && mangoAccount
|
||||
? formatFixedDecimals(
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount.getCollateralValue(group).toNumber()
|
||||
),
|
||||
false,
|
||||
true
|
||||
)
|
||||
: '–'}
|
||||
{group && mangoAccount ? (
|
||||
<FormatNumericValue
|
||||
value={toUiDecimalsForQuote(
|
||||
mangoAccount.getCollateralValue(group)
|
||||
)}
|
||||
decimals={2}
|
||||
isUsd
|
||||
/>
|
||||
) : (
|
||||
'–'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<Slippage />
|
||||
|
|
|
@ -15,8 +15,8 @@ import { PerpMarket, PerpPosition } from '@blockworks-foundation/mango-v4'
|
|||
import TableMarketName from './TableMarketName'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { formatDecimal } from 'utils/numbers'
|
||||
import ConnectEmptyState from '@components/shared/ConnectEmptyState'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
|
||||
const UnsettledTrades = ({
|
||||
unsettledSpotBalances,
|
||||
|
@ -198,10 +198,10 @@ const UnsettledTrades = ({
|
|||
<TableMarketName market={market} />
|
||||
</Td>
|
||||
<Td className="text-right font-mono">
|
||||
{formatDecimal(
|
||||
position.getUnsettledPnlUi(group, market),
|
||||
market.baseDecimals
|
||||
)}{' '}
|
||||
<FormatNumericValue
|
||||
value={position.getUnsettledPnlUi(group, market)}
|
||||
decimals={market.baseDecimals}
|
||||
/>{' '}
|
||||
<span className="font-body text-th-fgd-4">USDC</span>
|
||||
</Td>
|
||||
<Td>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { PublicKey } from '@solana/web3.js'
|
||||
import { formatDecimal, numberCompacter } from './numbers'
|
||||
import { formatNumericValue, numberCompacter } from './numbers'
|
||||
|
||||
export function abbreviateAddress(address: PublicKey, size = 5) {
|
||||
const base58 = address.toBase58()
|
||||
|
@ -11,5 +11,5 @@ export const formatYAxis = (value: number) => {
|
|||
? '0'
|
||||
: Math.abs(value) > 1
|
||||
? numberCompacter.format(value)
|
||||
: formatDecimal(value, 2)
|
||||
: formatNumericValue(value, 2)
|
||||
}
|
||||
|
|
140
utils/numbers.ts
140
utils/numbers.ts
|
@ -1,28 +1,93 @@
|
|||
import Decimal from 'decimal.js'
|
||||
|
||||
export const formatNumericValue = (
|
||||
value: number | string | Decimal,
|
||||
decimals?: number,
|
||||
roundUp?: boolean
|
||||
): string => {
|
||||
const numberValue = Number(value)
|
||||
let formattedValue
|
||||
if (numberValue > -0.0000000001 && numberValue < 0.000000001) {
|
||||
formattedValue = '0'
|
||||
} else if (decimals) {
|
||||
formattedValue = roundUp
|
||||
? roundValue(numberValue, decimals, true)
|
||||
: roundValue(numberValue, decimals)
|
||||
} else if (Math.abs(numberValue) >= 1000) {
|
||||
formattedValue = roundUp
|
||||
? roundValue(numberValue, 0, true)
|
||||
: roundValue(numberValue, 0)
|
||||
} else if (Math.abs(numberValue) >= 0.1) {
|
||||
formattedValue = roundUp
|
||||
? roundValue(numberValue, 3, true)
|
||||
: roundValue(numberValue, 3)
|
||||
} else {
|
||||
formattedValue = roundUp
|
||||
? roundValue(numberValue, 9, true)
|
||||
: roundValue(numberValue, 9)
|
||||
}
|
||||
return formattedValue
|
||||
}
|
||||
|
||||
export const formatCurrencyValue = (
|
||||
value: number | string | Decimal,
|
||||
decimals?: number
|
||||
): string => {
|
||||
const numberValue = Number(value)
|
||||
let formattedValue
|
||||
if (numberValue > -0.0000000001 && numberValue < 0.000000001) {
|
||||
formattedValue = '$0.00'
|
||||
} else if (decimals) {
|
||||
formattedValue = Intl.NumberFormat('en', {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals,
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
}).format(numberValue)
|
||||
} else if (Math.abs(numberValue) >= 1000) {
|
||||
formattedValue = usdFormatter0.format(numberValue)
|
||||
} else if (Math.abs(numberValue) >= 0.1) {
|
||||
formattedValue = usdFormatter2.format(numberValue)
|
||||
} else {
|
||||
formattedValue = usdFormatter3Sig.format(numberValue)
|
||||
}
|
||||
|
||||
if (formattedValue === '-$0.00') return '$0.00'
|
||||
return formattedValue
|
||||
}
|
||||
|
||||
const roundValue = (
|
||||
value: number | string | Decimal,
|
||||
decimals: number,
|
||||
roundUp?: boolean
|
||||
): string => {
|
||||
const decimalValue = value instanceof Decimal ? value : new Decimal(value)
|
||||
const roundMode = roundUp ? Decimal.ROUND_UP : Decimal.ROUND_FLOOR
|
||||
const roundedValue = decimalValue
|
||||
.toDecimalPlaces(decimals, roundMode)
|
||||
.toNumber()
|
||||
if (decimals === 2) return digits2.format(roundedValue)
|
||||
if (decimals === 3) return digits3.format(roundedValue)
|
||||
if (decimals === 4) return digits4.format(roundedValue)
|
||||
if (decimals === 5) return digits5.format(roundedValue)
|
||||
if (decimals === 6) return digits6.format(roundedValue)
|
||||
if (decimals === 7) return digits7.format(roundedValue)
|
||||
if (decimals === 8) return digits8.format(roundedValue)
|
||||
if (decimals === 9) return digits9.format(roundedValue)
|
||||
return roundedValue.toLocaleString(undefined, {
|
||||
maximumFractionDigits: decimals,
|
||||
})
|
||||
}
|
||||
|
||||
const digits2 = new Intl.NumberFormat('en', { maximumFractionDigits: 2 })
|
||||
const digits3 = new Intl.NumberFormat('en', { maximumFractionDigits: 3 })
|
||||
const digits4 = new Intl.NumberFormat('en', { maximumFractionDigits: 4 })
|
||||
const digits5 = new Intl.NumberFormat('en', { maximumFractionDigits: 5 })
|
||||
const digits6 = new Intl.NumberFormat('en', { maximumFractionDigits: 6 })
|
||||
const digits7 = new Intl.NumberFormat('en', { maximumFractionDigits: 7 })
|
||||
const digits8 = new Intl.NumberFormat('en', { maximumFractionDigits: 8 })
|
||||
const digits9 = new Intl.NumberFormat('en', { maximumFractionDigits: 9 })
|
||||
|
||||
export const formatDecimal = (
|
||||
value: number,
|
||||
decimals = 6,
|
||||
opts = { fixed: false }
|
||||
): string => {
|
||||
if (opts?.fixed) return value.toFixed(decimals)
|
||||
|
||||
if (value > -0.0000000001 && value < 0.000000001) return '0.00'
|
||||
|
||||
if (decimals === 2) return digits2.format(value)
|
||||
if (decimals === 5) return digits5.format(value)
|
||||
if (decimals === 6) return digits6.format(value)
|
||||
if (decimals === 8) return digits8.format(value)
|
||||
if (decimals === 9) return digits9.format(value)
|
||||
return value.toLocaleString(undefined, { maximumFractionDigits: decimals })
|
||||
}
|
||||
|
||||
export const numberFormat = new Intl.NumberFormat('en', {
|
||||
maximumSignificantDigits: 7,
|
||||
})
|
||||
|
@ -33,7 +98,7 @@ export const floorToDecimal = (
|
|||
): Decimal => {
|
||||
const decimal = value instanceof Decimal ? value : new Decimal(value)
|
||||
|
||||
return decimal.toDecimalPlaces(decimals, Decimal.ROUND_DOWN)
|
||||
return decimal.toDecimalPlaces(decimals, Decimal.ROUND_FLOOR)
|
||||
}
|
||||
|
||||
const usdFormatter0 = Intl.NumberFormat('en', {
|
||||
|
@ -50,43 +115,13 @@ const usdFormatter2 = Intl.NumberFormat('en', {
|
|||
currency: 'USD',
|
||||
})
|
||||
|
||||
const usdFormatter3 = Intl.NumberFormat('en', {
|
||||
const usdFormatter3Sig = Intl.NumberFormat('en', {
|
||||
minimumSignificantDigits: 3,
|
||||
maximumSignificantDigits: 3,
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
})
|
||||
|
||||
export const formatFixedDecimals = (
|
||||
value: number,
|
||||
isUSD?: boolean,
|
||||
is2DP?: boolean
|
||||
): string => {
|
||||
let formattedValue
|
||||
if (value === 0) {
|
||||
formattedValue = isUSD ? '$0.00' : '0'
|
||||
} else if (is2DP) {
|
||||
formattedValue = usdFormatter2.format(value)
|
||||
} else if (Math.abs(value) >= 1000) {
|
||||
formattedValue = isUSD
|
||||
? usdFormatter0.format(value)
|
||||
: Number(floorToDecimal(value, 0)).toLocaleString(undefined, {
|
||||
maximumFractionDigits: 0,
|
||||
})
|
||||
} else if (Math.abs(value) >= 0.1) {
|
||||
formattedValue = isUSD
|
||||
? usdFormatter2.format(value)
|
||||
: Number(floorToDecimal(value, 3)).toLocaleString(undefined, {
|
||||
maximumFractionDigits: 3,
|
||||
})
|
||||
} else {
|
||||
formattedValue = isUSD ? usdFormatter3.format(value) : digits9.format(value)
|
||||
}
|
||||
|
||||
if (formattedValue === '-$0.00') return '$0.00'
|
||||
return formattedValue
|
||||
}
|
||||
|
||||
export const countLeadingZeros = (x: number) => {
|
||||
if (x % 1 == 0) {
|
||||
return 0
|
||||
|
@ -95,13 +130,6 @@ export const countLeadingZeros = (x: number) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const trimDecimals = (n: number, digits: number) => {
|
||||
const step = Math.pow(10, digits || 0)
|
||||
const temp = Math.trunc(step * n)
|
||||
|
||||
return temp / step
|
||||
}
|
||||
|
||||
export const getDecimalCount = (value: number): number => {
|
||||
if (
|
||||
!isNaN(value) &&
|
||||
|
|
Loading…
Reference in New Issue