Skip to content

Commit 811aa05

Browse files
authored
cherry-pick: fix decimal places displayed on token value on permit pages (#25718)
1 parent 43cede8 commit 811aa05

File tree

11 files changed

+110
-30
lines changed

11 files changed

+110
-30
lines changed

test/e2e/tests/confirmations/signatures/permit.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ async function assertInfoValues(driver: Driver) {
8383
css: '.name__value',
8484
text: '0x5B38D...eddC4',
8585
});
86-
const value = driver.findElement({ text: '3000' });
86+
const value = driver.findElement({ text: '3,000' });
8787
const nonce = driver.findElement({ text: '0' });
8888
const deadline = driver.findElement({ text: '02 August 1971, 16:53' });
8989

ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ exports[`TypedSignInfo correctly renders permit sign type 1`] = `
401401
class="mm-box mm-text mm-text--body-md mm-box--color-inherit"
402402
style="white-space: pre-wrap;"
403403
>
404-
3000
404+
3,000
405405
</p>
406406
</div>
407407
</div>

ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/__snapshots__/permit-simulation.test.tsx.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ exports[`PermitSimulation renders component correctly 1`] = `
7070
<p
7171
class="mm-box mm-text mm-text--body-md mm-text--text-align-center mm-box--padding-inline-2 mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-xl"
7272
>
73-
3000
73+
30.00
7474
</p>
7575
</div>
7676
<div>

ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.test.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ describe('PermitSimulation', () => {
1515
},
1616
};
1717
const mockStore = configureMockStore([])(state);
18-
const { container } = renderWithProvider(<PermitSimulation />, mockStore);
18+
const { container } = renderWithProvider(
19+
<PermitSimulation tokenDecimals={2} />,
20+
mockStore,
21+
);
1922
expect(container).toMatchSnapshot();
2023
});
2124
});

ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ import {
2121
import { SignatureRequestType } from '../../../../../types/confirm';
2222
import useTokenExchangeRate from '../../../../../../../components/app/currency-input/hooks/useTokenExchangeRate';
2323
import { IndividualFiatDisplay } from '../../../../simulation-details/fiat-display';
24+
import { formatNumber } from '../../../utils';
2425
import { ConfirmInfoSection } from '../../../../../../../components/app/confirm/info/row/section';
2526

26-
const PermitSimulation: React.FC = () => {
27+
const PermitSimulation: React.FC<{
28+
tokenDecimals: number;
29+
}> = ({ tokenDecimals }) => {
2730
const t = useI18nContext();
2831
const currentConfirmation = useSelector(
2932
currentConfirmationSelector,
@@ -61,7 +64,10 @@ const PermitSimulation: React.FC = () => {
6164
paddingInline={2}
6265
textAlign={TextAlign.Center}
6366
>
64-
{value}
67+
{formatNumber(
68+
value / Math.pow(10, tokenDecimals),
69+
tokenDecimals,
70+
)}
6571
</Text>
6672
</Box>
6773
<Name value={verifyingContract} type={NameType.ETHEREUM_ADDRESS} />

ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import {
1010
} from '../../../../../../../test/data/confirmations/typed_sign';
1111
import TypedSignInfo from './typed-sign';
1212

13+
jest.mock('../../../../../../store/actions', () => {
14+
return {
15+
getTokenStandardAndDetails: jest.fn().mockResolvedValue({ decimals: 2 }),
16+
};
17+
});
18+
1319
describe('TypedSignInfo', () => {
1420
it('renders origin for typed sign data request', () => {
1521
const state = {

ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import { useSelector } from 'react-redux';
33
import { isValidAddress } from 'ethereumjs-util';
44

@@ -11,6 +11,7 @@ import {
1111
} from '../../../../../../components/app/confirm/info/row';
1212
import { useI18nContext } from '../../../../../../hooks/useI18nContext';
1313
import { currentConfirmationSelector } from '../../../../../../selectors';
14+
import { getTokenStandardAndDetails } from '../../../../../../store/actions';
1415
import { SignatureRequestType } from '../../../../types/confirm';
1516
import { isPermitSignatureRequest } from '../../../../utils';
1617
import { selectUseTransactionSimulations } from '../../../../selectors/preferences';
@@ -26,6 +27,7 @@ const TypedSignInfo: React.FC = () => {
2627
const useTransactionSimulations = useSelector(
2728
selectUseTransactionSimulations,
2829
);
30+
const [decimals, setDecimals] = useState<number>(0);
2931

3032
if (!currentConfirmation?.msgParams) {
3133
return null;
@@ -38,9 +40,23 @@ const TypedSignInfo: React.FC = () => {
3840

3941
const isPermit = isPermitSignatureRequest(currentConfirmation);
4042

43+
useEffect(() => {
44+
(async () => {
45+
if (!isPermit) {
46+
return;
47+
}
48+
const { decimals: tokenDecimals } = await getTokenStandardAndDetails(
49+
verifyingContract,
50+
);
51+
setDecimals(parseInt(tokenDecimals ?? '0', 10));
52+
})();
53+
}, [verifyingContract]);
54+
4155
return (
4256
<>
43-
{isPermit && useTransactionSimulations && <PermitSimulation />}
57+
{isPermit && useTransactionSimulations && (
58+
<PermitSimulation tokenDecimals={decimals} />
59+
)}
4460
<ConfirmInfoSection>
4561
{isPermit && (
4662
<>
@@ -64,6 +80,7 @@ const TypedSignInfo: React.FC = () => {
6480
<ConfirmInfoRowTypedSignData
6581
data={currentConfirmation.msgParams?.data as string}
6682
isPermit={isPermit}
83+
tokenDecimals={decimals}
6784
/>
6885
</ConfirmInfoRow>
6986
</ConfirmInfoSection>

ui/pages/confirmations/components/confirm/row/dataTree.tsx

+23-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
ConfirmInfoRowDate,
1212
ConfirmInfoRowText,
1313
} from '../../../../../components/app/confirm/info/row';
14+
import { formatNumber } from '../utils';
1415

1516
type ValueType = string | Record<string, TreeData> | TreeData[];
1617

@@ -22,9 +23,11 @@ export type TreeData = {
2223
export const DataTree = ({
2324
data,
2425
isPermit = false,
26+
tokenDecimals = 0,
2527
}: {
2628
data: Record<string, TreeData> | TreeData[];
2729
isPermit?: boolean;
30+
tokenDecimals?: number;
2831
}) => (
2932
<Box width={BlockSize.Full}>
3033
{Object.entries(data).map(([label, { value, type }], i) => (
@@ -42,6 +45,7 @@ export const DataTree = ({
4245
isPermit={isPermit}
4346
value={value}
4447
type={type}
48+
tokenDecimals={tokenDecimals}
4549
/>
4650
}
4751
</ConfirmInfoRow>
@@ -54,14 +58,32 @@ const DataField = ({
5458
isPermit,
5559
type,
5660
value,
61+
tokenDecimals,
5762
}: {
5863
label: string;
5964
isPermit: boolean;
6065
type: string;
6166
value: ValueType;
67+
tokenDecimals: number;
6268
}) => {
6369
if (typeof value === 'object' && value !== null) {
64-
return <DataTree data={value} isPermit={isPermit} />;
70+
return (
71+
<DataTree
72+
data={value}
73+
isPermit={isPermit}
74+
tokenDecimals={tokenDecimals}
75+
/>
76+
);
77+
}
78+
if (isPermit && label === 'value') {
79+
return (
80+
<ConfirmInfoRowText
81+
text={formatNumber(
82+
parseInt(value, 10) / Math.pow(10, tokenDecimals),
83+
tokenDecimals,
84+
)}
85+
/>
86+
);
6587
}
6688
if (isPermit && label === 'deadline') {
6789
return <ConfirmInfoRowDate date={parseInt(value, 10)} />;

ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ import {
77
ConfirmInfoRow,
88
ConfirmInfoRowText,
99
} from '../../../../../../components/app/confirm/info/row';
10-
11-
import { DataTree } from '../dataTree';
1210
import { parseSanitizeTypedDataMessage } from '../../../../utils';
11+
import { DataTree } from '../dataTree';
1312

1413
export const ConfirmInfoRowTypedSignData = ({
1514
data,
1615
isPermit,
16+
tokenDecimals,
1717
}: {
1818
data: string;
1919
isPermit?: boolean;
20+
tokenDecimals?: number;
2021
}) => {
2122
const t = useI18nContext();
2223

@@ -35,7 +36,11 @@ export const ConfirmInfoRowTypedSignData = ({
3536
<ConfirmInfoRowText text={primaryType} />
3637
</ConfirmInfoRow>
3738
<Box style={{ marginLeft: -8 }}>
38-
<DataTree data={sanitizedMessage.value} isPermit={isPermit} />
39+
<DataTree
40+
data={sanitizedMessage.value}
41+
isPermit={isPermit}
42+
tokenDecimals={tokenDecimals}
43+
/>
3944
</Box>
4045
</Box>
4146
);

ui/pages/confirmations/components/confirm/utils.test.ts

+28-18
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,39 @@ import {
88
unapprovedPersonalSignMsg,
99
} from '../../../../../test/data/confirmations/personal_sign';
1010
import { SignatureRequestType } from '../../types/confirm';
11-
import { getConfirmationSender } from './utils';
11+
import { formatNumber, getConfirmationSender } from './utils';
1212

13-
describe('getConfirmationSender()', () => {
14-
test("returns the sender address from a signature if it's passed", () => {
15-
const testCurrentConfirmation =
16-
genUnapprovedContractInteractionConfirmation() as TransactionMeta;
17-
const { from } = getConfirmationSender(testCurrentConfirmation);
13+
describe('confirm - utils', () => {
14+
describe('getConfirmationSender()', () => {
15+
test("returns the sender address from a signature if it's passed", () => {
16+
const testCurrentConfirmation =
17+
genUnapprovedContractInteractionConfirmation() as TransactionMeta;
18+
const { from } = getConfirmationSender(testCurrentConfirmation);
1819

19-
expect(from).toEqual(CONTRACT_INTERACTION_SENDER_ADDRESS);
20-
});
20+
expect(from).toEqual(CONTRACT_INTERACTION_SENDER_ADDRESS);
21+
});
2122

22-
test("returns the sender address from a transaction if it's passed", () => {
23-
const { from } = getConfirmationSender(
24-
unapprovedPersonalSignMsg as SignatureRequestType,
25-
);
23+
test("returns the sender address from a transaction if it's passed", () => {
24+
const { from } = getConfirmationSender(
25+
unapprovedPersonalSignMsg as SignatureRequestType,
26+
);
2627

27-
expect(from).toEqual(PERSONAL_SIGN_SENDER_ADDRESS);
28-
});
28+
expect(from).toEqual(PERSONAL_SIGN_SENDER_ADDRESS);
29+
});
2930

30-
test('returns no sender address if no confirmation is passed', () => {
31-
const testCurrentConfirmation = undefined;
32-
const { from } = getConfirmationSender(testCurrentConfirmation);
31+
test('returns no sender address if no confirmation is passed', () => {
32+
const testCurrentConfirmation = undefined;
33+
const { from } = getConfirmationSender(testCurrentConfirmation);
34+
35+
expect(from).toEqual(undefined);
36+
});
37+
});
3338

34-
expect(from).toEqual(undefined);
39+
describe('formatNumber()', () => {
40+
test('formats number according to decimal places passed', () => {
41+
expect(formatNumber(123456, 2)).toEqual('123,456.00');
42+
expect(formatNumber(123456, 0)).toEqual('123,456');
43+
expect(formatNumber(123456, 7)).toEqual('123,456.0000000');
44+
});
3545
});
3646
});

ui/pages/confirmations/components/confirm/utils.ts

+11
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,14 @@ export const getConfirmationSender = (
1717

1818
return { from };
1919
};
20+
21+
export const formatNumber = (value: number, decimals: number) => {
22+
if (value === undefined) {
23+
return value;
24+
}
25+
const formatter = new Intl.NumberFormat('en-US', {
26+
minimumFractionDigits: decimals,
27+
maximumFractionDigits: decimals,
28+
});
29+
return formatter.format(value);
30+
};

0 commit comments

Comments
 (0)