Skip to content

Commit 172a32e

Browse files
[BuyWidget] Handle very large numbers in FundWallet component
1 parent 85c4ef1 commit 172a32e

File tree

5 files changed

+97
-6
lines changed

5 files changed

+97
-6
lines changed

.changeset/legal-fans-enjoy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Handle very large numbers in BuyWidget

packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useRef, useState } from "react";
33
import type { Token } from "../../../../bridge/types/Token.js";
44
import type { ThirdwebClient } from "../../../../client/client.js";
55
import { type Address, getAddress } from "../../../../utils/address.js";
6+
import { numberToPlainString } from "../../../../utils/formatNumber.js";
67
import { useCustomTheme } from "../../../core/design-system/CustomThemeProvider.js";
78
import {
89
fontSize,
@@ -112,9 +113,9 @@ export function FundWallet({
112113
// Convert USD amount to token amount using token price
113114
const tokenAmount = usdAmount / uiOptions.destinationToken.priceUsd;
114115
// Format to reasonable decimal places (up to 6 decimals, remove trailing zeros)
115-
const formattedAmount = Number.parseFloat(
116-
tokenAmount.toFixed(6),
117-
).toString();
116+
const formattedAmount = numberToPlainString(
117+
Number.parseFloat(tokenAmount.toFixed(6)),
118+
);
118119
setAmount(formattedAmount);
119120
};
120121

packages/thirdweb/src/react/web/ui/Bridge/common/TokenAndChain.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,10 @@ function TokenIconWithFallback(props: {
138138
border: `1px solid ${theme.colors.borderColor}`,
139139
borderRadius: "50%",
140140
display: "flex",
141-
height: `${iconSize.md}px`,
141+
height: `${iconSize[props.size]}px`,
142142
justifyContent: "center",
143143
padding: spacing.xs,
144-
width: `${iconSize.md}px`,
144+
width: `${iconSize[props.size]}px`,
145145
}}
146146
>
147147
<Text

packages/thirdweb/src/utils/format-number.test.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from "vitest";
2-
import { formatNumber } from "./formatNumber.js";
2+
import { formatNumber, numberToPlainString } from "./formatNumber.js";
33

44
test("formatNumber", () => {
55
// no decimals
@@ -27,3 +27,49 @@ test("formatNumber", () => {
2727
expect(formatNumber(0.00000000000009, 3)).toEqual(0.001);
2828
expect(formatNumber(0.00000000000001, 3)).toEqual(0.001);
2929
});
30+
31+
test("numberToPlainString", () => {
32+
// Numbers without exponential notation (should return as-is)
33+
expect(numberToPlainString(123)).toEqual("123");
34+
expect(numberToPlainString(0.123)).toEqual("0.123");
35+
expect(numberToPlainString(0)).toEqual("0");
36+
expect(numberToPlainString(-456)).toEqual("-456");
37+
expect(numberToPlainString(-0.789)).toEqual("-0.789");
38+
39+
// Small numbers with negative exponents
40+
expect(numberToPlainString(1e-1)).toEqual("0.1");
41+
expect(numberToPlainString(1e-2)).toEqual("0.01");
42+
expect(numberToPlainString(1e-3)).toEqual("0.001");
43+
expect(numberToPlainString(1.23e-4)).toEqual("0.000123");
44+
expect(numberToPlainString(1.2345e-6)).toEqual("0.0000012345");
45+
expect(numberToPlainString(5e-10)).toEqual("0.0000000005");
46+
47+
// Large numbers with positive exponents - zerosNeeded >= 0
48+
expect(numberToPlainString(1e1)).toEqual("10");
49+
expect(numberToPlainString(1e2)).toEqual("100");
50+
expect(numberToPlainString(1.23e3)).toEqual("1230");
51+
expect(numberToPlainString(1.23e5)).toEqual("123000");
52+
expect(numberToPlainString(5.67e10)).toEqual("56700000000");
53+
54+
// Large numbers with positive exponents - zerosNeeded < 0 (decimal point insertion)
55+
expect(numberToPlainString(1.2345e2)).toEqual("123.45");
56+
expect(numberToPlainString(1.23e1)).toEqual("12.3");
57+
expect(numberToPlainString(9.876e2)).toEqual("987.6");
58+
expect(numberToPlainString(1.23456e3)).toEqual("1234.56");
59+
expect(numberToPlainString(5.4321e1)).toEqual("54.321");
60+
61+
// Edge cases where exponent equals decimal length
62+
expect(numberToPlainString(1.23e2)).toEqual("123");
63+
expect(numberToPlainString(1.234e3)).toEqual("1234");
64+
65+
// Negative numbers
66+
expect(numberToPlainString(-1.2345e2)).toEqual("-123.45");
67+
expect(numberToPlainString(-1.23e-4)).toEqual("-0.000123");
68+
69+
// Very large numbers (JavaScript precision limits apply)
70+
expect(numberToPlainString(1.0523871386385944e21)).toEqual("1052387138638594400000");
71+
72+
// Numbers that would normally show exponential notation
73+
expect(numberToPlainString(0.0000001)).toEqual("0.0000001");
74+
expect(numberToPlainString(10000000)).toEqual("10000000");
75+
});

packages/thirdweb/src/utils/formatNumber.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,42 @@ export function formatNumber(value: number, decimalPlaces: number) {
1414
const fn: "ceil" | "round" = value < threshold ? "ceil" : "round";
1515
return Math[fn]((value + Number.EPSILON) * precision) / precision;
1616
}
17+
18+
/**
19+
* Convert a number to a plain string, removing exponential notation
20+
* @internal
21+
*/
22+
export function numberToPlainString(num: number) {
23+
const str = num.toString();
24+
25+
// If no exponential notation, return as-is
26+
if (str.indexOf("e") === -1) {
27+
return str;
28+
}
29+
30+
// Parse exponential notation
31+
const parts = str.split("e");
32+
const coefficient = parts[0];
33+
const exponent = parseInt(parts[1] ?? "0");
34+
35+
// Handle negative exponents (small numbers)
36+
if (exponent < 0) {
37+
const zeros = "0".repeat(Math.abs(exponent) - 1);
38+
const digits = coefficient?.replace(".", "") || "";
39+
return `0.${zeros}${digits}`;
40+
}
41+
42+
// Handle positive exponents (large numbers)
43+
const [integer, decimal = ""] = coefficient?.split(".") || [];
44+
const zerosNeeded = exponent - decimal.length;
45+
46+
if (zerosNeeded >= 0) {
47+
return `${integer}${decimal}${"0".repeat(zerosNeeded)}`;
48+
} else {
49+
// When exponent < decimal.length, we need to insert decimal point
50+
// at the correct position: integer.length + exponent
51+
const insertAt = (integer?.length ?? 0) + exponent;
52+
const result = integer + decimal;
53+
return `${result.slice(0, insertAt)}.${result.slice(insertAt)}`;
54+
}
55+
}

0 commit comments

Comments
 (0)