docs(evm): clarify HBAR native value is tinybar inside the EVM (8 vs 18 decimals) - #700
Draft
Reccetech wants to merge 2 commits into
Draft
docs(evm): clarify HBAR native value is tinybar inside the EVM (8 vs 18 decimals)#700Reccetech wants to merge 2 commits into
Reccetech wants to merge 2 commits into
Conversation
…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>
Contributor
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
Contributor
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
Contributor
|
I think this is a welcome addition to the docs. Definitely makes it more clear on decimal caveats on Hedera. LGTM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Clarifies Hedera's decimal-handling docs, which imply
msg.valueis 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 thevaluepassed tocall/send/transferare 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 againstWHBAR.sol(deposit()mintsmsg.value;decimals = 8), a WETH differential test, and the consensus-node value-handling path.Changes (before → after)
1.
evm/differences/hbar-decimals.mdxTable — Smart Contract Service row
Hedera Smart Contract Service | 8 decimals | Within the EVM environment, HBAR maintains 8 decimal places, consistent with its native representation.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
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.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
JSON-RPC's use of 18 decimals ensures smooth integration with EVM tools and libraries.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:2.
evm/differences/native-token-transfers.mdxIntro sentence
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. …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): thevalueintransfer/send/callis tinybar;_amountin the examples is tinybar (1 HBAR = 100_000_000); passing1 ether/wei-scale values over-/under-transfers by 10^10.Example comment
// Transfer HBAR using different methods// 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
… Inside an EVM contract, msg.value, balance, and gasPrice all use 18 decimals; the relay handles the conversion. …… 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
/evm/differences/hbar-decimals.4.
evm/tokens/whbar.mdx(grounded inWHBAR.sol:deposit()mintsmsg.valuedirectly,decimals = 8)Decimals bullet
WHBAR (ERC20): Uses 8 decimal places (tinybars) and ONLY for deposits (wrapping) uses 18 decimal places (weibars).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
deposit()and send your HBAR asmsg.valuein weibars (10^18 per HBAR)" with contract examplewhbarContract.deposit{value: 10 * 10**18}();(= 1e19 tinybar → exceeds total HBAR supply → reverts)10 * 10**18, relay-converted); contract-to-contract must pass tinybar:<Check>"Decimal Nuance" noteAlthough the deposit() function requires input in 18 decimal weibars, WHBAR tokens and all related transfers and balances use 8 decimals …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"msg.value: The amount of HBAR sent along with the call.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.mdxAdded —
<Warning>at "Getting HBAR to the Contract" (new):msg.valueand the_amountpassed totransfer/send/callare tinybar (1 HBAR = 100_000_000); explains why the existingrequire(msg.value > 2000000000, …)guard (~20 HBAR) is tinybar-scale; don't pass1 ether/wei-scale values.Preview / checks
<Warning>callouts and Solidity code blocks (Mintlify;<Warning>is already used elsewhere in the docs)./evm/differences/hbar-decimalsresolve.