Skip to content

docs(evm): clarify HBAR native value is tinybar inside the EVM (8 vs 18 decimals) - #700

Draft
Reccetech wants to merge 2 commits into
mainfrom
docs/g53-fix-msgvalue-decimals-clarity
Draft

docs(evm): clarify HBAR native value is tinybar inside the EVM (8 vs 18 decimals)#700
Reccetech wants to merge 2 commits into
mainfrom
docs/g53-fix-msgvalue-decimals-clarity

Conversation

@Reccetech

@Reccetech Reccetech commented Jul 30, 2026

Copy link
Copy Markdown

What

Clarifies Hedera's decimal-handling docs, which imply msg.value is 18-decimal wei inside a contract — contradicting the same table's row stating the Smart Contract Service uses 8 decimals, and leading developers into a 10^10 scaling error. This aligns six pages to the verified behavior.

Verified behavior (all pages now reflect this)

Inside the EVM, msg.value, address(this).balance, and the value passed to call/send/transfer are tinybar (8 decimals). The JSON-RPC relay converts only the transaction envelope (weibar → tinybar, ÷10^10) before execution; contract-to-contract calls are not converted. Confirmed against WHBAR.sol (deposit() mints msg.value; decimals = 8), a WETH differential test, and the consensus-node value-handling path.


Changes (before → after)

1. evm/differences/hbar-decimals.mdx

Table — Smart Contract Service row

  • Before: Hedera Smart Contract Service | 8 decimals | Within the EVM environment, HBAR maintains 8 decimal places, consistent with its native representation.
  • After: Hedera Smart Contract Service (EVM execution) | 8 decimals | Within the EVM, HBAR is tinybar-scaled: msg.value, address(this).balance, and the value passed to call/send/transfer are all 8 decimals during execution.

Table — msg.value row

  • Before: JSON-RPC Relay (msg.value) | 18 decimals | For compatibility with EVM tooling, msg.value in JSON-RPC Relay represents HBAR with 18 decimal places. Consequently, gasPrice also uses 18 decimal places in this context.
  • After: JSON-RPC Relay (msg.value / gasPrice) — RPC boundary only | 18 decimals | Ethereum tooling submits and reads the transaction value and gasPrice in 18-decimal weibar at the JSON-RPC boundary. The relay converts weibar to tinybar (÷10^10) before the EVM executes, so the msg.value your contract actually sees is 8-decimal tinybar — not 18-decimal wei. See the warning below.

Key Impacts — 3rd bullet

  • Before: JSON-RPC's use of 18 decimals ensures smooth integration with EVM tools and libraries.
  • After: The 18-decimal representation is a JSON-RPC boundary convention only — inside the EVM, native value is tinybar (8 decimals). Do not assume msg.value is wei-scale (see warning).

Added — <Warning> block (new): inside a contract, native value is tinybar (8 decimals), not wei (18); covers the relay-path under-count and the contract-to-contract case, with a broken-vs-correct example:

// ❌ BROKEN — `1 ether` (1e18) treated as tinybar (= 10^10 HBAR)
(bool ok, ) = payable(vault).call{value: 1 ether}("");
// ✅ CORRECT — tinybar (1 HBAR = 100,000,000)
(bool ok, ) = payable(vault).call{value: 100000000}("");

2. evm/differences/native-token-transfers.mdx

Intro sentence

  • Before: Fortunately, the core Solidity patterns—like using transfer(), send(), or call()—work the same way on Hedera, making it easy for developers familiar with EVM. …
  • After: The core Solidity patterns—transfer(), send(), and call()—are supported on Hedera, with one important difference: the value (and msg.value) is denominated in tinybar (8 decimals) during EVM execution, not wei (18 decimals). …

Added — <Warning> after Key Considerations (new): the value in transfer/send/call is tinybar; _amount in the examples is tinybar (1 HBAR = 100_000_000); passing 1 ether/wei-scale values over-/under-transfers by 10^10.

Example comment

  • Before: // Transfer HBAR using different methods
  • After: // Transfer HBAR using different methods. + // NOTE: _amount is in TINYBAR (8 decimals), not wei — 1 HBAR = 100_000_000.

3. evm/development/troubleshooting.mdx — "Decimal handling: 8 vs 18" (was factually incorrect)

Paragraph

  • Before: … Inside an EVM contract, msg.value, balance, and gasPrice all use 18 decimals; the relay handles the conversion. …
  • After: … The JSON-RPC relay converts a transaction's value and gasPrice from 18-decimal weibar to 8-decimal tinybar before the EVM runs — so inside a contract, msg.value, address(this).balance, and the value in call/send/transfer are all tinybar (8 decimals), not wei. + two "trap" bullets (don't assume wei; contract-to-contract not converted).

Code example

  • Before:
    // Inside a contract, msg.value is in 18-decimal wei (as on Ethereum).
    function deposit() external payable {
        require(msg.value >= 1 ether, "send at least 1 HBAR");   // always fails: 1 HBAR = 1e8, not 1e18
    }
  • After:
    // msg.value is TINYBAR inside the contract: 1 HBAR = 1e8, not 1 ether (1e18).
    function deposit() external payable {
        require(msg.value >= 1e8, "send at least 1 HBAR"); // 1e8 tinybar = 1 HBAR
    }
  • Added a link to /evm/differences/hbar-decimals.

4. evm/tokens/whbar.mdx (grounded in WHBAR.sol: deposit() mints msg.value directly, decimals = 8)

Decimals bullet

  • Before: WHBAR (ERC20): Uses 8 decimal places (tinybars) and ONLY for deposits (wrapping) uses 18 decimal places (weibars).
  • After: WHBAR (ERC20): Uses 8 decimal places (tinybars) throughout … deposit() simply mints an amount of WHBAR equal to the msg.value it receives, and msg.value is tinybar during EVM execution. The 18-decimal weibar form is only the transaction value an off-chain caller submits; the relay converts it to tinybar before deposit() runs.

Deposit guidance + example

  • Before: "call deposit() and send your HBAR as msg.value in weibars (10^18 per HBAR)" with contract example whbarContract.deposit{value: 10 * 10**18}(); (= 1e19 tinybar → exceeds total HBAR supply → reverts)
  • After: split into two paths — off-chain callers send weibar (10 * 10**18, relay-converted); contract-to-contract must pass tinybar:
    // Contract-to-contract `value` is TINYBAR (8 decimals): 1 HBAR = 1e8.
    function wrapTenHbar() public {
        whbarContract.deposit{value: 10 * 10**8}(); // 10 HBAR
    }

<Check> "Decimal Nuance" note

  • Before: Although the deposit() function requires input in 18 decimal weibars, WHBAR tokens and all related transfers and balances use 8 decimals …
  • After: deposit() mints WHBAR equal to msg.value, and msg.value is tinybar (8 decimals) during execution — WHBAR is 8-decimal throughout. The 18-decimal weibar form applies only to the value an off-chain caller puts in the transaction; a contract calling deposit{value: X} must pass tinybar (1 HBAR = 1e8).

5. evm/development/deploying.mdx — "Impacted Variables"

  • Before: msg.value: The amount of HBAR sent along with the call.
  • After: msg.value: The HBAR sent along with the call, in tinybar (8 decimals) — not wei. A 1 HBAR transfer is msg.value == 1e8. See Decimal Handling.

6. evm/tutorials/intermediate/send-receive-hbar.mdx

Added — <Warning> at "Getting HBAR to the Contract" (new): msg.value and the _amount passed to transfer/send/call are tinybar (1 HBAR = 100_000_000); explains why the existing require(msg.value > 2000000000, …) guard (~20 HBAR) is tinybar-scale; don't pass 1 ether/wei-scale values.


Preview / checks

  • Renders the <Warning> callouts and Solidity code blocks (Mintlify; <Warning> is already used elsewhere in the docs).
  • Internal links to /evm/differences/hbar-decimals resolve.

…18 decimals)

The decimals table implied `msg.value` is 18-decimal wei, contradicting the
row that (correctly) states the Smart Contract Service uses 8 decimals. A
developer reading "JSON-RPC Relay (msg.value): 18 decimals" assumes wei-scale
and gets a 10^10 error: a WETH-style deposit records balances 10^10 too small,
and a contract-to-contract `call{value: 1 ether}` sends 1e18 *as tinybar*
(over-/under-transfer).

- hbar-decimals.mdx: mark the 18-decimal row as an RPC-boundary convention,
  note the relay converts weibar->tinybar before execution, and add a warning
  with worked examples (relay path under-count; contract-to-contract call).
- native-token-transfers.mdx: state that `value`/`msg.value` is tinybar during
  execution; warn against `1 ether`/wei-scale amounts; annotate the example.

Signed-off-by: Keith Kowal <keith.kowal@hashgraph.com>
…, deploy & tutorial

Follow-up to the hbar-decimals fix: the docs disagreed on whether msg.value is
tinybar or wei inside a contract. This aligns the remaining pages to the
verified behavior — inside the EVM, msg.value / balance / call-value are tinybar
(8 decimals); the relay converts only the transaction envelope (weibar) before
execution; contract-to-contract calls are NOT converted.

- troubleshooting.mdx: the "Decimal handling" section stated msg.value is
  18-decimal wei inside a contract and used a broken `require(msg.value >= 1 ether)`
  example (1 HBAR arrives as 1e8, so it always failed). Corrected to tinybar,
  added the two-path traps + a fixed example.
- whbar.mdx: WHBAR.sol deposit() mints msg.value directly (no internal
  conversion; decimals = 8). Removed the claim that deposit "requires 18-decimal
  weibars" and fixed the contract-to-contract example from {value: 10*10**18}
  (=1e19 tinybar, exceeds total supply, reverts) to {value: 10*10**8} = 10 HBAR;
  split off-chain (weibar, relay-converted) vs contract (tinybar) paths.
- deploying.mdx: note msg.value is tinybar (not wei) + link.
- send-receive-hbar.mdx: add a tinybar warning explaining the existing
  `require(msg.value > 2000000000)` guard.

Signed-off-by: Keith Kowal <keith.kowal@hashgraph.com>
@mintlify

mintlify Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
hedera-docs 🟢 Ready View Preview Jul 30, 2026, 6:29 PM

@mintlify

mintlify Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
hedera-docs 🟡 Building Jul 30, 2026, 6:28 PM

@Reccetech Reccetech self-assigned this Jul 30, 2026
@kpachhai

Copy link
Copy Markdown
Contributor

I think this is a welcome addition to the docs. Definitely makes it more clear on decimal caveats on Hedera. LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants