Skip to content

fix: strip leading zero digits from value in eth_estimateGas requests - #9797

Merged
dan437 merged 3 commits into
mainfrom
conf-1740-estimate-gas-strip-leading-zeros
Aug 6, 2026
Merged

fix: strip leading zero digits from value in eth_estimateGas requests#9797
dan437 merged 3 commits into
mainfrom
conf-1740-estimate-gas-strip-leading-zeros

Conversation

@dan437

@dan437 dan437 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Explanation

Some RPC nodes strictly parse hex quantities (Go's hexutil) and reject eth_estimateGas requests when the transaction value contains leading zero digits, e.g. 0x00 or 0x0de0b6b3a7640000:

json: cannot unmarshal hex number with leading zero digits into Go struct field TransactionArgs.value of type *hexutil.Big

Dapp libraries commonly pad hex to an even byte length (e.g. ethers v6 toBeHex(0) returns 0x00), so dapp-provided values can hit this on strict chains. When the estimate call fails, the controller silently falls back to a percentage of the block gas limit, which can exceed a chain's per-transaction gas cap and cause every submission to fail.

This change normalizes value in the eth_estimateGas request built by estimateGas():

  • Strips leading zero digits from strict hex strings (0x000x0, 0x0de0b6b3a76400000xde0b6b3a7640000).
  • Keeps the existing nullish default (0x0).
  • Leaves non-hex input untouched so it still fails into the fallback path as before.

data is intentionally not touched — it is bytes, not a quantity, so leading zeros are semantic there.

References

  • Related to CONF-1740
  • Same failure mode as fix: gas limit estimation  #4897, which fixed the gas field by removing computed fields from the estimate request; value cannot be removed, so it is normalized instead

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Low Risk
Small, localized change to gas-estimate request shaping with explicit tests; no auth or submission-path changes.

Overview
Fixes gas estimation failures on RPC nodes that reject non-canonical hex quantities in eth_estimateGas (e.g. Go hexutil rejecting 0x00 or 0x0de0b6b3a7640000), which often comes from dapp libraries padding value to even byte length.

estimateGas() now runs transaction value through a new normalizeValue helper before the RPC call: nullish still becomes 0x0, strict hex strings lose leading zero digits, and non-hex input is left unchanged so existing error/fallback behavior is preserved. data is unchanged (byte data, not a quantity).

Tests cover the value matrix; the changelog documents the fix.

Reviewed by Cursor Bugbot for commit 4f81422. Bugbot is set up for automated code reviews on this repo. Configure here.

@matthewwalsh0
matthewwalsh0 requested a review from jpuri August 6, 2026 12:36
@dan437
dan437 added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit 17cded9 Aug 6, 2026
142 checks passed
@dan437
dan437 deleted the conf-1740-estimate-gas-strip-leading-zeros branch August 6, 2026 12:47
pull Bot pushed a commit to firas9941/metamask-mobile that referenced this pull request Aug 7, 2026
## **Description**

Bumps `@metamask/transaction-controller` from 69.5.0 to 69.5.1
(dependency range and resolutions pin) to pick up the `eth_estimateGas`
fix from
[MetaMask/core#9797](MetaMask/core#9797): the
`value` field is now normalized to a canonical hex quantity (leading
zero digits stripped, e.g. `0x00` → `0x0`, `0x0de0b6b3a7640000` →
`0xde0b6b3a7640000`) before the estimation request is sent.

Some RPC nodes use strict hex-quantity parsing (e.g. Go's `hexutil`) and
reject quantities with leading zero digits. When a dapp submitted a
transaction with a padded value (as some ethers.js `toBeHex()` usages
produce), gas estimation failed on those networks and transactions could
not be sent.

Lockfile updated with `yarn install --mode=update-lockfile`.

## **Changelog**

CHANGELOG entry: Fixed gas estimation failing on networks whose RPC
nodes reject hex values with leading zeros (such as `0x00`)

## **Related issues**

Fixes:
[CONF-1740](https://consensyssoftware.atlassian.net/browse/CONF-1740)

## **Manual testing steps**

```gherkin
Feature: gas estimation with non-canonical hex value

  Scenario: dapp sends a transaction with a leading-zero value
    Given a network whose RPC rejects hex quantities with leading zeros (e.g. Robinhood Chain)
    And a dapp connected to the wallet

    When the dapp calls eth_sendTransaction with value "0x00"
    Then the confirmation opens and gas estimation succeeds
    And the eth_estimateGas request carries value "0x0"
```

## **Screenshots/Recordings**

N/A — dependency bump, no UI change.

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

[CONF-1740]:
https://consensyssoftware.atlassian.net/browse/CONF-1740?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches the core transaction/gas-estimation path via a patch bump
only; behavior change is narrow but affects all EVM sends that estimate
gas.
> 
> **Overview**
> Upgrades **`@metamask/transaction-controller`** from **69.5.0** to
**69.5.1** in `package.json` (dependency range and resolutions pin) and
refreshes **`yarn.lock`**. There are no mobile app source changes.
> 
> The new patch pulls in upstream behavior that **canonicalizes
transaction `value` to hex quantity** before **`eth_estimateGas`**, so
padded values like `0x00` or `0x0de0b6b3a7640000` are sent as `0x0` /
`0xde0b6b3a7640000`. That unblocks gas estimation and sending on RPCs
that reject non-canonical hex (e.g. strict Go `hexutil` parsers).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a9fc379. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants