Skip to content

Commit

Permalink
fix: format units according to asset decimals + unknown asset (#115)
Browse files Browse the repository at this point in the history
Closes FE-31

this PR address fully the format of amounts being showed across the
explorer. will format to assets decimal config OR format the raw amount
if it’s a unknown asset (unknown asset decimals)
- update to `fuels/assets@0.1.3`  to get new asset utils functions
- share assetId with components that didn’t have it
- apply correct amount formatted to this pages/components
  - BalanceItem
  - Utxos
  - TxAssetItem
  - TxInput
  - TxOutput
  • Loading branch information
LuizAsFight authored Nov 15, 2023
1 parent 9351a8b commit fe981bd
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 32 deletions.
2 changes: 1 addition & 1 deletion packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@fuel-explorer/graphql": "workspace:*",
"@fuel-ts/math": "0.67.0",
"@fuel-wallet/sdk": "0.13.7",
"@fuels/assets": "0.1.1",
"@fuels/assets": "0.1.3",
"@fuels/ui": "workspace:*",
"@tabler/icons-react": "2.40.0",
"@tanstack/react-query": "5.8.3",
Expand Down
5 changes: 3 additions & 2 deletions packages/app/src/systems/Asset/hooks/useAsset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ export function useAsset(assetId?: string) {
return {
assetId,
name: found?.name ?? 'Unknown Asset',
symbol: found?.symbol ?? null,
icon: found?.icon ?? null,
symbol: found?.symbol || '',
icon: found?.icon || '',
networks: found?.networks ?? [],
};
}, [assetId]);
}
12 changes: 12 additions & 0 deletions packages/app/src/systems/Asset/hooks/useFuelAsset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { CHAIN_IDS, getAssetFuel } from '@fuels/assets';
import type { Asset } from '@fuels/assets';
import { useMemo } from 'react';

export const useFuelAsset = (asset?: Asset | null) => {
const fuelAsset = useMemo(
() => (asset ? getAssetFuel(asset, CHAIN_IDS.fuel.beta4) : undefined),
[asset?.symbol, asset?.name, asset?.networks.length],
);

return fuelAsset;
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import {
import { bn } from 'fuels';
import Image from 'next/image';
import { useAsset } from '~/systems/Asset/hooks/useAsset';
import { useFuelAsset } from '~/systems/Asset/hooks/useFuelAsset';
import { TxIcon } from '~/systems/Transaction/component/TxIcon/TxIcon';

import { formatZeroUnits } from '../../utils/format';
import type { UtxoItem } from '../Utxos/Utxos';
import { Utxos } from '../Utxos/Utxos';

Expand All @@ -31,8 +33,9 @@ export const BalanceItem = createComponent<
render: (_, { item, ...props }) => {
const assetId = item.assetId;
const amount = item.amount;
const asset = useAsset(assetId);
const { isMobile } = useBreakpoints();
const asset = useAsset(assetId);
const fuelAsset = useFuelAsset(asset);
if (!asset) return null;

const hasUTXOs = !!item.utxos?.length;
Expand Down Expand Up @@ -66,7 +69,17 @@ export const BalanceItem = createComponent<
</VStack>
{amount && (
<Text className="text-secondary">
{bn(amount).format()} {asset.symbol}
{fuelAsset?.decimals ? (
<>
{bn(amount).format({
precision: fuelAsset.decimals,
units: fuelAsset.decimals,
})}{' '}
{asset.symbol}
</>
) : (
formatZeroUnits(amount)
)}
</Text>
)}
</Flex>
Expand Down
47 changes: 38 additions & 9 deletions packages/app/src/systems/Core/components/Utxos/Utxos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,27 @@ import { bn } from 'fuels';
import NextLink from 'next/link';
import { VariableSizeList as List } from 'react-window';
import { tv } from 'tailwind-variants';
import { useAsset } from '~/systems/Asset/hooks/useAsset';
import { useFuelAsset } from '~/systems/Asset/hooks/useFuelAsset';

import { formatZeroUnits } from '../../utils/format';

export type UtxoItem = Partial<Omit<TUtxoItem, '__typename'>>;

type UtxoItemProps = {
item: UtxoItem;
assetId?: string;
style?: React.CSSProperties;
};

function UtxoItem({ item, style }: UtxoItemProps) {
function UtxoItem({ item, style, assetId }: UtxoItemProps) {
const { isMobile } = useBreakpoints();
const asset = useAsset(assetId);
const fuelAsset = useFuelAsset(asset);

if (!item.utxoId) return null;
if (!asset) return null;

const classes = styles();
const trim = isMobile ? 8 : 16;
return (
Expand All @@ -49,7 +58,16 @@ function UtxoItem({ item, style }: UtxoItemProps) {
</Address>
<Text className="text-secondary flex items-center gap-2">
<Icon icon={IconCoins} size={14} />{' '}
{bn(item.amount).format({ precision: isMobile ? 3 : undefined })}{' '}
{fuelAsset?.decimals ? (
<>
{bn(item.amount).format({
precision: isMobile ? 3 : undefined,
units: fuelAsset.decimals,
})}{' '}
</>
) : (
formatZeroUnits(item.amount || '')
)}
</Text>
</Box>
);
Expand All @@ -60,7 +78,7 @@ type UtxosProps = BoxProps & {
items?: UtxoItem[] | null;
};

function VirtualList({ items }: UtxosProps) {
function VirtualList({ items, assetId }: UtxosProps) {
const { isMobile } = useBreakpoints();
return (
<List
Expand All @@ -71,19 +89,30 @@ function VirtualList({ items }: UtxosProps) {
>
{({ index: idx, style }) => {
const item = items?.[idx];
return item && <UtxoItem key={item.utxoId} style={style} item={item} />;
return (
item && (
<UtxoItem
key={item.utxoId}
style={style}
item={item}
assetId={assetId}
/>
)
);
}}
</List>
);
}

function CommonList({ items }: UtxosProps) {
function CommonList({ items, assetId }: UtxosProps) {
return (
items?.map((item) => <UtxoItem key={item.utxoId} item={item} />) ?? null
items?.map((item) => (
<UtxoItem key={item.utxoId} item={item} assetId={assetId} />
)) ?? null
);
}

export function Utxos({ items, ...props }: UtxosProps) {
export function Utxos({ items, assetId, ...props }: UtxosProps) {
const len = items?.length ?? 0;
return (
<Collapsible.Content {...props}>
Expand All @@ -92,9 +121,9 @@ export function Utxos({ items, ...props }: UtxosProps) {
</Collapsible.Title>
<Collapsible.Body className="p-0">
{len > 10 ? (
<VirtualList items={items} />
<VirtualList items={items} assetId={assetId} />
) : (
<CommonList items={items} />
<CommonList items={items} assetId={assetId} />
)}
</Collapsible.Body>
</Collapsible.Content>
Expand Down
13 changes: 13 additions & 0 deletions packages/app/src/systems/Core/utils/format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { BNInput } from 'fuels';
import { bn } from 'fuels';

/**
* Formats the given amount by multiplying it by 10 and formatting it with 1 unit.
* This is a workaround because formatting with zero units doesn't work.
* @param amount - The amount to format.
* @returns The formatted amount.
*/
export function formatZeroUnits(amount: BNInput) {
const formatted = bn(amount).mul(10).format({ units: 1, precision: 0 });
return formatted;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { CardProps } from '@fuels/ui';
import { Text, Card, EntityItem, HStack, cx } from '@fuels/ui';
import { Text, Card, EntityItem, HStack, cx, useBreakpoints } from '@fuels/ui';
import { IconArrowDown, IconArrowUp } from '@tabler/icons-react';
import { bn } from 'fuels';
import type { BN } from 'fuels';
import Image from 'next/image';
import { useMemo } from 'react';
import { findAssetById } from '~/systems/Core/utils/asset';
import { useAsset } from '~/systems/Asset/hooks/useAsset';
import { useFuelAsset } from '~/systems/Asset/hooks/useFuelAsset';
import { formatZeroUnits } from '~/systems/Core/utils/format';

import { TxIcon } from '../TxIcon/TxIcon';

Expand All @@ -24,9 +25,11 @@ export function TxAssetItem({
amountOut,
...props
}: TxAssetItemProps) {
const asset = useMemo(() => findAssetById(assetId), [assetId]);
const assetName = asset?.name ?? 'Unknown';
const assetSymbol = asset?.symbol ?? null;
const asset = useAsset(assetId);
const { isMobile } = useBreakpoints();
const fuelAsset = useFuelAsset(asset);
if (!asset) return null;

return (
<Card {...props} className={cx('gap-2 pb-2', className)}>
<EntityItem className="px-4 pb-4 border-b border-border">
Expand All @@ -42,22 +45,42 @@ export function TxAssetItem({
<TxIcon type="Mint" status="Submitted" />
)}
</EntityItem.Slot>
<EntityItem.Info id={assetId} title={assetName} />
<EntityItem.Info id={assetId} title={asset.name} />
</EntityItem>
<HStack className="px-4 justify-between">
<Text
className="text-sm"
iconColor="text-success"
leftIcon={IconArrowUp}
>
{bn(amountIn).format()} {assetSymbol}
{fuelAsset?.decimals ? (
<>
{bn(amountIn).format({
precision: isMobile ? 3 : undefined,
units: fuelAsset.decimals,
})}{' '}
</>
) : (
formatZeroUnits(amountIn)
)}
{asset.symbol}
</Text>
<Text
className="text-sm"
iconColor="text-error"
leftIcon={IconArrowDown}
>
{bn(amountOut).format()} {assetSymbol}
{fuelAsset?.decimals ? (
<>
{bn(amountOut).format({
precision: isMobile ? 3 : undefined,
units: fuelAsset.decimals,
})}{' '}
</>
) : (
formatZeroUnits(amountOut)
)}
{asset.symbol}
</Text>
</HStack>
</Card>
Expand Down
18 changes: 15 additions & 3 deletions packages/app/src/systems/Transaction/component/TxInput/TxInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import Image from 'next/image';
import NextLink from 'next/link';
import { tv } from 'tailwind-variants';
import { useAsset } from '~/systems/Asset/hooks/useAsset';
import { useFuelAsset } from '~/systems/Asset/hooks/useFuelAsset';
import type { UtxoItem } from '~/systems/Core/components/Utxos/Utxos';
import { Utxos } from '~/systems/Core/components/Utxos/Utxos';
import { formatZeroUnits } from '~/systems/Core/utils/format';

import { TxIcon } from '../TxIcon/TxIcon';

Expand All @@ -36,10 +38,11 @@ const TxInputCoin = createComponent<TxInputProps, typeof Collapsible>({
const assetId = input.assetId;
const amount = input.totalAmount;
const inputs = input.inputs as InputCoin[];
const asset = useAsset(assetId);
const { isMobile } = useBreakpoints();

const asset = useAsset(assetId);
const fuelAsset = useFuelAsset(asset);
if (!asset) return null;

return (
<Collapsible {...props}>
<Collapsible.Header>
Expand Down Expand Up @@ -91,7 +94,16 @@ const TxInputCoin = createComponent<TxInputProps, typeof Collapsible>({
*/}
{amount && (
<Text className="text-secondary hidden tablet:block">
{bn(amount).format({ precision: isMobile ? 3 : undefined })}{' '}
{fuelAsset?.decimals ? (
<>
{bn(amount).format({
precision: isMobile ? 3 : undefined,
units: fuelAsset.decimals,
})}{' '}
</>
) : (
formatZeroUnits(amount)
)}
{asset.symbol}
</Text>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import Image from 'next/image';
import NextLink from 'next/link';
import { tv } from 'tailwind-variants';
import { useAsset } from '~/systems/Asset/hooks/useAsset';
import { useFuelAsset } from '~/systems/Asset/hooks/useFuelAsset';
import { formatZeroUnits } from '~/systems/Core/utils/format';

import { TxIcon } from '../TxIcon/TxIcon';

Expand All @@ -36,8 +38,9 @@ const TxOutputCoin = createComponent<TxOutputProps, typeof Card>({
const assetId = output.assetId;
const amount = output.totalAmount;
const asset = useAsset(assetId);

const fuelAsset = useFuelAsset(asset);
if (!asset) return null;

return (
<Card {...props} className={cx('py-3', props.className)}>
<Card.Header className={classes.header()}>
Expand Down Expand Up @@ -84,7 +87,16 @@ const TxOutputCoin = createComponent<TxOutputProps, typeof Card>({
<HStack align="center" className="hidden tablet:block">
{amount && (
<Text className="text-secondary">
{bn(amount).format(isMobile ? { precision: 3 } : undefined)}{' '}
{fuelAsset?.decimals ? (
<>
{bn(amount).format({
precision: isMobile ? 3 : undefined,
units: fuelAsset.decimals,
})}{' '}
</>
) : (
formatZeroUnits(amount)
)}
{asset.symbol}
</Text>
)}
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit fe981bd

Please sign in to comment.