Skip to content

Commit

Permalink
refactor format amount (#459)
Browse files Browse the repository at this point in the history
  • Loading branch information
Thykof authored Jun 11, 2024
1 parent c595674 commit e5c4eb2
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 173 deletions.
6 changes: 2 additions & 4 deletions src/components/DollarValue/DollarValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react';
import { ComponentPropsWithoutRef } from 'react';
import { FiAlertTriangle } from 'react-icons/fi';
import { Tooltip } from '../Tooltip';
import { formatFTAmount, parseAmount } from '../../lib/util/parseAmount';
import { formatAmount, parseAmount } from '../../lib/util/parseAmount';

export interface DollarValueProps extends ComponentPropsWithoutRef<'p'> {
dollarValue?: string;
Expand All @@ -31,9 +31,7 @@ export function DollarValue(props: DollarValueProps) {

let dollarValueFormatted = '';
if (dollarValue !== undefined && dollarValue !== '') {
const dollarValueBigInt = parseAmount(dollarValue, 2);
const { amountFormattedPreview } = formatFTAmount(dollarValueBigInt, 2);
dollarValueFormatted = amountFormattedPreview;
dollarValueFormatted = formatAmount(parseAmount(dollarValue, 2), 2).preview;
}

if (dollarValue !== undefined && dollarValue !== '') {
Expand Down
11 changes: 4 additions & 7 deletions src/components/Token/Token.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { FiTrash2 } from 'react-icons/fi';
import { Button } from '../Button';
import { Tooltip } from '../Tooltip';
import { DollarValue } from '../DollarValue';
import { formatFTAmount } from '../../lib/util/parseAmount';
import { formatAmount } from '../../lib/util/parseAmount';

export interface TokenProps extends ComponentPropsWithoutRef<'div'> {
logo?: React.ReactNode;
Expand Down Expand Up @@ -41,12 +41,9 @@ export function Token(props: TokenProps) {
let bigintBalance = BigInt(0);
if (balance !== '') {
bigintBalance = BigInt(balance);
const { amountFormattedPreview, amountFormattedFull } = formatFTAmount(
bigintBalance,
decimals,
);
rawBalance = amountFormattedFull;
formattedBalance = amountFormattedPreview;
const { preview, full } = formatAmount(bigintBalance, decimals);
rawBalance = full;
formattedBalance = preview;
} else {
formattedBalance = undefined;
rawBalance = undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/ConnectMassaWallets/components/MASBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function MASBalance() {
const formattedBalance = formatAmount(
fromMAS(balance?.candidateBalance || '0').toString(),
9,
).amountFormattedFull;
).full;

return (
<div className="flex gap-2 mas-body">
Expand Down
10 changes: 5 additions & 5 deletions src/lib/util/handlePercent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('handlePercent', () => {
18,
'ETH',
);
expect(result).toBe('0.250000000000000000');
expect(result).toBe('0.25');
});

it('should return correctly formatted amount when symbol is massaToken and newAmount is within balance', () => {
Expand All @@ -24,7 +24,7 @@ describe('handlePercent', () => {
9,
massaToken,
);
expect(result).toBe('0.500000000');
expect(result).toBe('0.5');
});

it('should return 0 when balance minus fees is less than 0', () => {
Expand All @@ -36,7 +36,7 @@ describe('handlePercent', () => {
9,
massaToken,
);
expect(result).toBe('0.000000000');
expect(result).toBe('0');
});

it('should return balance minus fees when newAmount exceeds balance', () => {
Expand All @@ -48,11 +48,11 @@ describe('handlePercent', () => {
9,
massaToken,
);
expect(result).toBe('0.900000000');
expect(result).toBe('0.9');
});

it('should handle zero amount correctly', () => {
const result = handlePercent(0n, 10n, 0n, 1000n, 9, massaToken);
expect(result).toBe('0.000000000');
expect(result).toBe('0');
});
});
2 changes: 1 addition & 1 deletion src/lib/util/handlePercent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ export function handlePercent(
}
}

return formatAmount(newAmount.toString(), decimals).amountFormattedFull;
return formatAmount(newAmount.toString(), decimals).full;
}
45 changes: 45 additions & 0 deletions src/lib/util/parseAmount.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { formatAmount } from './parseAmount';

export default { title: 'Amount/Format' };

const inputs = [
'123456789123456789',
'1234567891234567890000',
'1234567',
'123',
'0',
'',
'1000000000200000000',
'1000000000',
'1000000000000000000',
'1000000000000000000234',
'1000000000000000000000000000000000',
'1000000000000000000000000000000001',
];

export const _FormatAmount = {
render: () => {
return (
<div className="mas-body text-f-primary">
<p>input: preview / full</p>
{[2, 9, 18].map((decimals) => {
return (
<>
<h2 className="mas-subtitle">
Format amount that have {decimals} decimals
</h2>
{inputs.map((input) => {
const { preview, full } = formatAmount(input, decimals);
return (
<p>
{input}: {preview} / {full}
</p>
);
})}
</>
);
})}
</div>
);
},
};
135 changes: 65 additions & 70 deletions src/lib/util/parseAmount.test.ts
Original file line number Diff line number Diff line change
@@ -1,161 +1,156 @@
import {
formatAmount,
formatStandard,
roundDecimalPartToOneSignificantDigit,
roundDecimalPartToTwoSignificantDigit,
} from './parseAmount';

describe('formatAmount', () => {
test('formats an empty string', () => {
const result = formatAmount('', 18);
expect(result).toEqual({
amountFormattedPreview: '0.0',
amountFormattedFull: '0.000000000000000000',
preview: '0',
full: '0',
});
});

test('formats an amount with default parameters', () => {
const result = formatAmount('123456789012345678901', 18);
expect(result).toEqual({
amountFormattedPreview: '123.46',
amountFormattedFull: '123.456789012345678901',
preview: '123.46',
full: '123.456789012345678901',
});
});

test('formats an amount with BigInt', () => {
const result = formatAmount(123456789012345678901n, 18);
expect(result).toEqual({
preview: '123.46',
full: '123.456789012345678901',
});
});

test('formats an amount with less than the specified decimals', () => {
const result = formatAmount('12345', 8);
expect(result).toEqual({
amountFormattedPreview: '0.0001',
amountFormattedFull: '0.00012345',
preview: '0.00012',
full: '0.00012345',
});
});

test('formats an amount with custom separator', () => {
const result = formatAmount('123456789012345678901', 9, "'");
expect(result).toEqual({
amountFormattedPreview: "123'456'789'012.35",
amountFormattedFull: "123'456'789'012.345678901",
preview: "123'456'789'012.35",
full: "123'456'789'012.345678901",
});
});

test('adds padding zeroes when necessary', () => {
const result = formatAmount('1', 18, ',');
expect(result).toEqual({
amountFormattedPreview: '0.000000000000000001',
amountFormattedFull: '0.000000000000000001',
preview: '0.000000000000000001',
full: '0.000000000000000001',
});
});

test('handles amount with exact decimals length', () => {
const result = formatAmount('1000000000000000000', 18);
expect(result).toEqual({
amountFormattedPreview: '1.00',
amountFormattedFull: '1.000000000000000000',
preview: '1',
full: '1',
});
});

test('formats an amount with less than the specified decimals and round up', () => {
const result = formatAmount('69000', 9);
const result = formatAmount('69500', 9);
expect(result).toEqual({
amountFormattedPreview: '0.00007',
amountFormattedFull: '0.000069000',
preview: '0.00007',
full: '0.0000695',
});
});
});

describe('roundDecimalPartToOneSignificantDigit', () => {
test("should return '0' when all digits are zero", () => {
expect(roundDecimalPartToOneSignificantDigit('000')).toEqual('0');
});

test('should handle a single zero without leading zeroes', () => {
expect(roundDecimalPartToOneSignificantDigit('0')).toEqual('0');
});

test('should handle a single digit without rounding', () => {
expect(roundDecimalPartToOneSignificantDigit('4')).toEqual('4');
});

test('should round down when the second digit is less than 5', () => {
expect(roundDecimalPartToOneSignificantDigit('004300')).toEqual('004');
});

test('should round up when the second digit is 5 or more', () => {
expect(roundDecimalPartToOneSignificantDigit('00046')).toEqual('0005');
});

test('should round up and handle carry-over with trailing zeroes', () => {
expect(roundDecimalPartToOneSignificantDigit('0099')).toEqual('01');
});
});

describe('formatStandard', () => {
test('formats an empty string', () => {
const result = formatStandard('', 18);
const result = formatAmount('', 18).full;
expect(result).toEqual('0');
});

test('formats an amount with default parameters', () => {
const result = formatStandard('123456789012345678901', 18);
const result = formatAmount('123456789012345678901', 18).full;
expect(result).toEqual('123.456789012345678901');
});

test('formats an amount with less than the specified decimals', () => {
const result = formatStandard('12345', 8);
const result = formatAmount('12345', 8).full;
expect(result).toEqual('0.00012345');
});

test('adds padding zeroes when necessary', () => {
const result = formatStandard('1', 18);
const result = formatAmount('1', 18).full;
expect(result).toEqual('0.000000000000000001');
});

test('handles amount with exact decimals length', () => {
const result = formatStandard('1000000000000000000', 18);
const result = formatAmount('1000000000000000000', 18).full;
expect(result).toEqual('1');
});

test('formats an amount with less than the specified decimals and round up', () => {
const result = formatStandard('69000', 9);
const result = formatAmount('69000', 9).full;
expect(result).toEqual('0.000069');
});

it('formatStandard with min string value', () => {
it('formatAmount with min string value', () => {
const value = '0000000000';

const result = formatStandard(value.toString());

const result = formatAmount(value.toString()).full;
expect(result).toBe('0');
});

it('formatStandard with min bigint value', () => {
it('formatAmount with min bigint value', () => {
const value = 0n;

const result = formatStandard(value.toString());

const result = formatAmount(value.toString()).full;
expect(result).toBe('0');
});

it('formatStandard with mid range string value', () => {
it('formatAmount with mid range string value', () => {
const value = '10000000000000';

const result = formatStandard(value.toString());

const result = formatAmount(value.toString()).full;
expect(result).toBe('10,000');
});

it('formatStandard with mid range bigint value', () => {
it('formatAmount with mid range bigint value', () => {
const value = 10000000000000n;

const result = formatStandard(value.toString());

const result = formatAmount(value.toString()).full;
expect(result).toBe('10,000');
});

it('formatStandard with max string value', () => {
it('formatAmount with max string value', () => {
const value = '922337203600000000000';
const result = formatAmount(value.toString()).full;
expect(result).toBe('922,337,203,600');
});
});

const result = formatStandard(value.toString());
describe('roundDecimalPartToOneSignificantDigit', () => {
test("should return '0' when all digits are zero", () => {
expect(roundDecimalPartToTwoSignificantDigit('000')).toEqual('0');
});

expect(result).toBe('922,337,203,600');
test('should handle a single zero without leading zeroes', () => {
expect(roundDecimalPartToTwoSignificantDigit('0')).toEqual('0');
});

test('should handle a single digit without rounding', () => {
expect(roundDecimalPartToTwoSignificantDigit('4')).toEqual('4');
});

test('should round down when the second digit is less than 5', () => {
expect(roundDecimalPartToTwoSignificantDigit('0043100')).toEqual('0043');
});

test('should round up when the second digit is 5 or more', () => {
expect(roundDecimalPartToTwoSignificantDigit('000468')).toEqual('00047');
});

test('should round up and handle carry-over with trailing zeroes', () => {
expect(roundDecimalPartToTwoSignificantDigit('0099')).toEqual('0099');
});
});
Loading

0 comments on commit e5c4eb2

Please sign in to comment.