Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions ui-react/src/__tests__/utils/text.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import BigNumber from 'bignumber.js';
import {
getThemeColor,
checkIsExtrinsicIndex,
formatBalanceAmount,
formatHash,
formatNumber,
getBalanceAmount,
Expand Down Expand Up @@ -92,6 +93,20 @@ describe('Utils - text', () => {
});
});

describe('formatBalanceAmount', () => {
it('should compact million-scale balances', () => {
expect(formatBalanceAmount(new BigNumber('12064779'))).toBe('12.0648 Million');
});

it('should keep ordinary balances readable', () => {
expect(formatBalanceAmount(new BigNumber('255969555555555554095805'), 18)).toBe('255,969.555556');
});

it('should keep small balances readable', () => {
expect(formatBalanceAmount(new BigNumber('123456789'), 18)).toBe('< 0.00000001');
});
});

describe('timeAgo', () => {
const mockNow = new Date(2025, 5, 15, 12, 0, 0).getTime(); // 2025-05-15 12:00:00

Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/components/account/accountTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'

import { BareProps } from '@/types/page'
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Spinner } from '@heroui/react'
import { formatHash, getBalanceAmount, getThemeColor } from '@/utils/text'
import { formatBalanceAmount, formatHash, getThemeColor } from '@/utils/text'
import { getExtrinsicListParams, unwrap, useAccounts } from '@/utils/api'
import { PAGE_SIZE } from '@/utils/const'
import { useData } from '@/context'
Expand Down Expand Up @@ -67,7 +67,7 @@ const Component: React.FC<Props> = ({ children, className, args }) => {
<TableRow key={item.address}>
{(columnKey) => {
if (columnKey === 'balance') {
return <TableCell>{getBalanceAmount(new BigNumber(item.balance), token?.decimals).toFormat()}</TableCell>
return <TableCell>{formatBalanceAmount(new BigNumber(item.balance), token?.decimals)}</TableCell>
} else if (columnKey === 'address') {
return (
<TableCell>
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/components/erc20Token/tokenHolderTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKey
import { getPVMTokenHolderListParams, pvmTokenType, unwrap, usePVMTokenHolders } from '@/utils/api'
import { PAGE_SIZE } from '@/utils/const'
import BigNumber from 'bignumber.js'
import { getBalanceAmount, getThemeColor } from '@/utils/text'
import { formatBalanceAmount, getThemeColor } from '@/utils/text'
import { Link } from '../link'
import { CursorPagination } from '../cursorPagination'
import { env } from 'next-runtime-env'
Expand Down Expand Up @@ -73,7 +73,7 @@ const Component: React.FC<Props> = ({ args, token, children, className }) => {
</TableCell>
)
} else if (columnKey === 'balance') {
return <TableCell>{getBalanceAmount(new BigNumber(item.balance), token.decimals).toFormat()}</TableCell>
return <TableCell>{formatBalanceAmount(new BigNumber(item.balance), token.decimals)}</TableCell>
}
return <TableCell>{getKeyValue(item, columnKey)}</TableCell>
}}
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/components/erc20Token/tokenTransferTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '@/utils/api'
import { PAGE_SIZE } from '@/utils/const'
import BigNumber from 'bignumber.js'
import { formatHash, getBalanceAmount, getThemeColor, timeAgo } from '@/utils/text'
import { formatBalanceAmount, formatHash, getThemeColor, timeAgo } from '@/utils/text'
import { Link } from '../link'
import { CursorPagination } from '../cursorPagination'
import { env } from 'next-runtime-env'
Expand Down Expand Up @@ -90,7 +90,7 @@ const Component: React.FC<Props> = ({ args, token, children, className }) => {
} else if (columnKey === 'value') {
return (
<TableCell>
{getBalanceAmount(new BigNumber(item.value), item.decimals).toFormat()} {item.symbol}
{formatBalanceAmount(new BigNumber(item.value), item.decimals)} {item.symbol}
</TableCell>
)
} else if (columnKey === 'create_at') {
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/components/pvmAccount/accountTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'

import { BareProps } from '@/types/page'
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Spinner } from '@heroui/react'
import { getBalanceAmount, getThemeColor } from '@/utils/text'
import { formatBalanceAmount, getThemeColor } from '@/utils/text'
import { getExtrinsicListParams, unwrap, usePVMAccounts } from '@/utils/api'
import { PAGE_SIZE } from '@/utils/const'
import { useData } from '@/context'
Expand Down Expand Up @@ -66,7 +66,7 @@ const Component: React.FC<Props> = ({ children, className, args }) => {
<TableRow key={item.evm_account}>
{(columnKey) => {
if (columnKey === 'balance') {
return <TableCell>{getBalanceAmount(new BigNumber(item.balance), token?.decimals).toFormat()}</TableCell>
return <TableCell>{formatBalanceAmount(new BigNumber(item.balance), token?.decimals)}</TableCell>
} else if (columnKey === 'address') {
return (
<TableCell>
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/components/pvmAccount/tokenTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Table, Pagination, TableHeader, TableColumn, TableBody, TableRow, Table
import { getPVMAccountTokenListParams, getPVMTokenTransferListParams, pvmTokenType, unwrap, usePVMAccountTokens } from '@/utils/api'
import { PAGE_SIZE } from '@/utils/const'
import BigNumber from 'bignumber.js'
import { formatHash, getBalanceAmount, getThemeColor, timeAgo } from '@/utils/text'
import { formatBalanceAmount, formatHash, getThemeColor, timeAgo } from '@/utils/text'
import { Link } from '../link'
import { env } from 'next-runtime-env'

Expand Down Expand Up @@ -55,7 +55,7 @@ const Component: React.FC<Props> = ({ args, token, children, className }) => {
<TableRow key={item.contract}>
{(columnKey) => {
if (columnKey === 'balance') {
return <TableCell>{getBalanceAmount(new BigNumber(item.balance), item.decimals).toFormat()}</TableCell>
return <TableCell>{formatBalanceAmount(new BigNumber(item.balance), item.decimals)}</TableCell>
} else if (columnKey === 'name') {
return <TableCell>{`${item.name}(${item.symbol})`}</TableCell>
} else if (columnKey === 'category') {
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/components/transfer/transferTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'

import { BareProps } from '@/types/page'
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Spinner } from '@heroui/react'
import { formatHash, getBalanceAmount, getThemeColor, timeAgo } from '@/utils/text'
import { formatBalanceAmount, formatHash, getThemeColor, timeAgo } from '@/utils/text'
import { getTransferListParams, unwrap, useTransfers } from '@/utils/api'
import { PAGE_SIZE } from '@/utils/const'
import { useData } from '@/context'
Expand Down Expand Up @@ -81,7 +81,7 @@ const Component: React.FC<Props> = ({ children, className, args }) => {
} else if (columnKey === 'block_timestamp') {
return <TableCell>{timeAgo(item.block_timestamp)}</TableCell>
} else if (columnKey === 'amount') {
return <TableCell>{getBalanceAmount(new BigNumber(item.amount), token?.decimals).toFormat()}</TableCell>
return <TableCell>{formatBalanceAmount(new BigNumber(item.amount), token?.decimals)}</TableCell>
}
if (columnKey === 'sender' || columnKey === 'receiver') {
const address = columnKey === 'sender' ? item.sender : item.receiver
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/components/tx/txTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'

import { BareProps } from '@/types/page'
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Spinner } from '@heroui/react'
import { formatHash, getBalanceAmount, getThemeColor, timeAgo } from '@/utils/text'
import { formatBalanceAmount, formatHash, getThemeColor, timeAgo } from '@/utils/text'
import { getPVMTxListParams, unwrap, usePVMTxs } from '@/utils/api'
import { PAGE_SIZE, PVM_DECIMAL } from '@/utils/const'
import { useData } from '@/context'
Expand Down Expand Up @@ -83,7 +83,7 @@ const Component: React.FC<Props> = ({ children, className, args }) => {
</TableCell>
)
} else if (columnKey === 'value') {
return <TableCell>{getBalanceAmount(new BigNumber(item.value), PVM_DECIMAL).toFormat()}</TableCell>
return <TableCell>{formatBalanceAmount(new BigNumber(item.value), PVM_DECIMAL)}</TableCell>
} else if (columnKey === 'block_num') {
return (
<TableCell>
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/pages/address/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { CardBody, Card, Tabs, Tab } from '@heroui/react'
import { useRouter } from 'next/router'
import { getBalanceAmount, getThemeColor } from '@/utils/text'
import { formatBalanceAmount, getThemeColor } from '@/utils/text'
import { unwrap, usePVMAccounts } from '@/utils/api'
import { useData } from '@/context'
import BigNumber from 'bignumber.js'
Expand Down Expand Up @@ -44,7 +44,7 @@ export default function Page() {
<div className="flex items-center">
<div className="w-48">Balance</div>
<div>
{getBalanceAmount(new BigNumber(accountData.balance), token?.decimals).toFormat()} {token?.symbol}
{formatBalanceAmount(new BigNumber(accountData.balance), token?.decimals)} {token?.symbol}
</div>
</div>
</CardBody>
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/pages/contract/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { CardBody, Card, Tabs, Tab, Divider } from '@heroui/react'
import { useRouter } from 'next/router'
import { getBalanceAmount, getThemeColor } from '@/utils/text'
import { formatBalanceAmount, getThemeColor } from '@/utils/text'
import { unwrap, usePVMAccounts, usePVMContract } from '@/utils/api'
import { useData } from '@/context'
import { TxTable } from '@/components/tx'
Expand Down Expand Up @@ -69,7 +69,7 @@ export default function Page() {
<div className="flex items-center">
<div className="w-48">Balance</div>
<div>
{getBalanceAmount(new BigNumber(accountData?.balance || 0), token?.decimals).toFormat()} {token?.symbol}
{formatBalanceAmount(new BigNumber(accountData?.balance || 0), token?.decimals)} {token?.symbol}
</div>
</div>
<Divider className="my-2.5" />
Expand Down
28 changes: 22 additions & 6 deletions ui-react/src/pages/sub/account/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react'
import { CardBody, Card, Divider, Tabs, Tab } from '@heroui/react'
import { useRouter } from 'next/router'
import { getBalanceAmount, getThemeColor } from '@/utils/text'
import { formatBalanceAmount, getThemeColor } from '@/utils/text'
import { unwrap, useAccount } from '@/utils/api'
import { useData } from '@/context'
import BigNumber from 'bignumber.js'
Expand All @@ -22,6 +22,7 @@ export default function Page() {
})

const accountData = unwrap(data)
const tokenSymbol = token?.symbol ? ` ${token.symbol}` : ''

const transferable = useMemo(() => {
if (accountData) {
Expand Down Expand Up @@ -56,27 +57,42 @@ export default function Page() {
<CardBody>
<div className="flex items-center">
<div className="w-48">Total Balance</div>
<div>{getBalanceAmount(new BigNumber(accountData.balance), token?.decimals).toFormat()}</div>
<div>
{formatBalanceAmount(new BigNumber(accountData.balance), token?.decimals)}
{tokenSymbol}
</div>
</div>
<Divider className="my-2.5" />
<div className="flex items-center">
<div className="w-48">Transferrable</div>
<div>{getBalanceAmount(transferable, token?.decimals).toFormat()}</div>
<div>
{formatBalanceAmount(transferable, token?.decimals)}
{tokenSymbol}
</div>
</div>
<Divider className="my-2.5" />
<div className="flex items-center">
<div className="w-48">Locked</div>
<div>{getBalanceAmount(new BigNumber(accountData.locked), token?.decimals).toFormat()}</div>
<div>
{formatBalanceAmount(new BigNumber(accountData.locked), token?.decimals)}
{tokenSymbol}
</div>
</div>
<Divider className="my-2.5" />
<div className="flex items-center">
<div className="w-48">Vested</div>
<div>{getBalanceAmount(new BigNumber(accountData.vested || 0), token?.decimals).toFormat()}</div>
<div>
{formatBalanceAmount(new BigNumber(accountData.vested || 0), token?.decimals)}
{tokenSymbol}
</div>
</div>
<Divider className="my-2.5" />
<div className="flex items-center">
<div className="w-48">Reserved</div>
<div>{getBalanceAmount(new BigNumber(accountData.reserved), token?.decimals).toFormat()}</div>
<div>
{formatBalanceAmount(new BigNumber(accountData.reserved), token?.decimals)}
{tokenSymbol}
</div>
</div>
</CardBody>
</Card>
Expand Down
4 changes: 2 additions & 2 deletions ui-react/src/pages/token/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { CardBody, Card, Tabs, Tab, Divider } from '@heroui/react'
import { useRouter } from 'next/router'
import { getBalanceAmount, getThemeColor } from '@/utils/text'
import { formatBalanceAmount, getThemeColor } from '@/utils/text'
import { unwrap, usePVMTokens } from '@/utils/api'
import { useData } from '@/context'
import BigNumber from 'bignumber.js'
Expand Down Expand Up @@ -53,7 +53,7 @@ export default function Page() {
<Divider className="my-2.5" />
<div className="flex items-center">
<div className="w-48">Token Supply</div>
<div>{getBalanceAmount(new BigNumber(tokenData.totalSupply), tokenData.decimals).toFormat()}</div>
<div>{formatBalanceAmount(new BigNumber(tokenData.totalSupply), tokenData.decimals)}</div>
</div>
<Divider className="my-2.5" />
<div className="flex items-center">
Expand Down
8 changes: 4 additions & 4 deletions ui-react/src/pages/tx/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react'
import { CardBody, Card, Divider } from '@heroui/react'
import { useRouter } from 'next/router'
import { getBalanceAmount, getUTCTime, timeAgo } from '@/utils/text'
import { formatBalanceAmount, getUTCTime, timeAgo } from '@/utils/text'
import { unwrap, usePVMTx } from '@/utils/api'
import { Container, PageContent } from '@/ui'
import { PVM_DECIMAL } from '@/utils/const'
Expand Down Expand Up @@ -87,7 +87,7 @@ export default function Page() {
<Divider className="my-2.5" />
<div className="flex items-center">
<div className="w-48">Value</div>
<div>{getBalanceAmount(new BigNumber(extrinsicData.value), PVM_DECIMAL).toFormat()}</div>
<div>{formatBalanceAmount(new BigNumber(extrinsicData.value), PVM_DECIMAL)}</div>
</div>
<Divider className="my-2.5" />
<div className="flex items-center">
Expand All @@ -110,12 +110,12 @@ export default function Page() {
<div className="flex items-center">
<div className="w-48">Txn Fee</div>
<div>
{getBalanceAmount(
{formatBalanceAmount(
new BigNumber(extrinsicData.gas_used).times(
extrinsicData.txn_type === 2 ? extrinsicData.effective_gas_price : extrinsicData.gas_price
),
PVM_DECIMAL
).toFormat()}
)}
</div>
</div>
<Divider className="my-2.5" />
Expand Down
30 changes: 30 additions & 0 deletions ui-react/src/utils/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,36 @@ export function getBalanceAmount(amount: BigNumber, decimals?: number): BigNumbe
return new BigNumber(amount).dividedBy(BIG_TEN.pow(decimals || 0))
}

const COMPACT_BALANCE_UNITS = [
{ value: new BigNumber('1000000000000'), label: 'Trillion' },
{ value: new BigNumber('1000000000'), label: 'Billion' },
{ value: new BigNumber('1000000'), label: 'Million' },
] as const

export function formatBalanceAmount(amount: BigNumber, decimals?: number): string {
const balance = getBalanceAmount(amount, decimals)
const absBalance = balance.abs()
const compactUnit = COMPACT_BALANCE_UNITS.find((unit) => absBalance.isGreaterThanOrEqualTo(unit.value))

if (compactUnit) {
return `${balance.dividedBy(compactUnit.value).decimalPlaces(4, BigNumber.ROUND_HALF_UP).toFormat(4)} ${compactUnit.label}`
}

if (absBalance.isZero()) {
return '0'
}

if (absBalance.isLessThan(1)) {
if (absBalance.isLessThan('0.00000001')) {
return balance.isNegative() ? '> -0.00000001' : '< 0.00000001'
}

return balance.decimalPlaces(8, BigNumber.ROUND_HALF_UP).toFormat()
}

return balance.decimalPlaces(6, BigNumber.ROUND_HALF_UP).toFormat()
}

export function timeAgo(time: number | string, now = Date.now()) {
const second = +time * 1000
const d = new Date(second)
Expand Down