MetaMask / MetaMask/metamask-extension

Signature confirmation crashes with "BigNumber Error: times() number type has more than 15 significant digits" when rendering `eth_signTypedData_v4` in the popup window

Open
#44,319 2 comments 1 reaction 0 assignees View on GitHub
external-contributor INVALID-ISSUE-TEMPLATE Sev1 ta-needs-engineer-escalation ta-triaged team-confirmations
Dominant language
TypeScript
Stars
13.2k
Forks
5.6k
Avg merge
2d 5h
Merged PRs (30d)
451

Description

## Describe the bug
When a dApp requests `eth_signTypedData_v4` and MetaMask is running as a **popup / detached window**, the confirmation screen fails to render. Instead of the signature UI, MetaMask shows **"MetaMask encountered an error - Your information can't be shown."**

The error card reports:

```
BigNumber Error: times() number type has more than 15 significant digits: 0.07619191169906189
Code: BigNumber Error
```

The **identical** request renders and signs correctly when MetaMask is docked to the **side panel**. So the defect is specific to the popup rendering / typed-data decoding path, not to the request.

This reproduces with all other browser extensions disabled and is independent of any third-party extension. It also reproduces across Chromium browsers (confirmed in both Chrome and Brave), so it is not browser-specific.

## Steps to reproduce
1. Run MetaMask in the default **popup** mode (not docked to the side panel).
2. Go to `polymarket.com`, connect the wallet on Polygon, and place a CLOB order (Buy / Sell).
3. Polymarket requests `eth_signTypedData_v4` for a `Polymarket CTF Exchange` `Order` (payload below).
4. The popup shows "MetaMask encountered an error" with the BigNumber error, instead of the signature confirmation.
5. Dock MetaMask to the **side panel** and retry the identical order -> it renders and signs correctly.

## Expected behavior
The popup renders the typed-data signature confirmation (same as the side panel) and lets the user sign or reject. A display-only value that cannot be formatted should degrade to "details unavailable" rather than crashing the whole confirmation.

## Analysis
`bignumber.js` in DEBUG mode throws when a `BigNumber` is constructed from - or multiplied by - a primitive JS `number` with more than 15 significant digits. `0.07619191169906189` has 17. Somewhere in the popup's signature-decode / preview path a raw float is passed into `new BigNumber(x)` / `.times(x)` instead of a string. Every frame in the stack is a MetaMask bundle:

```
BigNumber Error: times() number type has more than 15 significant digits: 0.07619191169906189
at $ (vendor-cdd60c62..js:3:39085) // BigNumber error ctor
at new N (vendor-cdd60c62..js:3:37286) // new BigNumber(...)
at _.times._.mul (vendor-cdd60c62..js:3:48852) // .times()
at _ (133..js:1:106345) // signature decode / preview
at p (133..js:1:104321)
at g (133..js:1:104967)
at v (133..js:1:5667)
at G (133..js:1:157066)
... React reconciler (vendor-5a94f17d..js) ...
```

Note: the wallet's simulation returns `{ "stateChanges": [], "error": "Unsupported signature" }` for this request. That is expected and unrelated (an off-chain order signature has no on-chain state change); it is not the cause of the crash.

## Request payload
```json
{
"method": "eth_signTypedData_v4",
"origin": "https://polymarket.com",
"params": [
"0x",
{
"domain": {
"name": "Polymarket CTF Exchange",
"version": "2",
"chainId": "137",
"verifyingContract": "0xe111180000d2663c0091e4f400237545b87b996b"
},
"primaryType": "Order",
"message": {
"salt": "1673202389268",
"maker": "0x",
"signer": "0x",
"tokenId": "113899799237951007160327893359215790094139814320491939136784205037742098170284",
"makerAmount": "1000000",
"takerAmount": "1004010",
"timestamp": "1783622778949",
"side": "0",
"signatureType": "2",
"metadata": "0x0000000000000000000000000000000000000000000000000000000000000000",
"builder": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
}
]
}
```
All `message` fields are integer strings / hex. No float is present in the payload - the `0.07619191169906189` value is derived inside MetaMask's preview rendering.

## Suggested fix
1. Construct BigNumbers from **strings**, never from primitive JS numbers, in the signature-decode / preview path: `new BigNumber(String(x))` / `bn.times(x.toString())` (or round with `.toFixed()` first).
2. Wrap the preview computation so a formatting failure degrades gracefully instead of unmounting the whole confirmation - a display-only value should never block signing.
3. Reconcile the popup path with the side-panel path, which already handles this value correctly.

## Environment
- **MetaMask** 13.38.2 - **popup / detached-window** mode reproduces; **side panel** does not.
- Reproduced in **two Chromium browsers** on macOS (arm64):
- Chrome 149.0.7827.201 (Official Build, arm64)
- Brave 1.92.134 (Official Build, arm64) / Chromium 150.0.7871.63
- macOS (Darwin 24.5.0).
- dApp: `polymarket.com`, Polymarket CTF Exchange v2 `Order`, chain 137 (Polygon).

---
Reported by Yoaz Shmider, Kerberus Cyber Security .

Contributor guide

Open the contributing guide

Research direction

Start by tracing the popup signature-decode and preview path referenced by the stack, then compare it with the side-panel rendering path, using the vendor-cdd60c62 and 133 bundle references as entry points. Reproduce with the supplied eth_signTypedData_v4 payload and verify that the popup renders the confirmation and handles an unformatable display value without blocking signing.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.