Coinatio Research
Token Creation7 min read

Token Decimals Explained: Base Units, Display Values, and Common Bugs

Token ledgers store integers. Decimals tell software where to place a decimal point when presenting those integers to people. They do not add floating-point arithmetic to a contract, determine a token price, or make a token divisible beyond its smallest integer unit. Many integration failures come from confusing a displayed amount with the raw amount transferred onchain.

Editorial research by Coinatio, checked against the primary documentation cited below. Educational content only.

Editorial illustration for Token Decimals Explained: Base Units, Display Values, and Common Bugs
Key takeaways
  • Raw amounts are integers, while display amounts are raw amounts divided by ten raised to the decimals value.
  • Never use binary floating-point numbers for token accounting or transaction construction.
  • Read decimals from the canonical contract or mint and cache them with the asset identity and network.
  • Normalize both assets by decimals before calculating prices, pool ratios, or portfolio values.

The conversion model

If a token has d decimals, one displayed token equals 10^d base units. A raw balance of 1,250,000 with six decimals displays as 1.25. To construct a transfer of 1.25, parse the user string as decimal text and produce the integer 1,250,000. The reverse operation formats the integer using the known scale. Preserve trailing precision according to product needs, but never change the underlying integer.

JavaScript Number cannot exactly represent every large integer and introduces rounding for many decimal fractions. Use bigint for raw values and a decimal-string parser or a well-tested arbitrary-precision library at input boundaries. Reject excess fractional digits rather than silently rounding a transaction amount. APIs should identify whether each field is raw or formatted, ideally through naming such as amountRaw and amountUi.

Ethereum and Solana behavior

In ERC-20, decimals is optional metadata used for display. OpenZeppelin defaults to 18 and allows an implementation to override decimals. Core transfer and balance methods still use integers. Integrators should call decimals on the deployed address, handle a valid zero value, and avoid assuming 18 merely because it is common. A malicious or nonstandard contract may revert or return unexpected data, so indexers need validation and an explicit unknown state.

An SPL Token mint records decimals when the mint is initialized. Token instructions that include checked variants, such as TransferChecked, validate the supplied decimals against the mint, helping clients detect mismatches. Solana RPC can return both raw amount and uiAmountString. Prefer the decimal string for display because a numeric uiAmount can lose precision. Token-2022 follows the same base-unit model even when extensions add transfer fees or interest-bearing presentation.

Pricing and supply consequences

A pool price is a ratio between normalized token quantities. Suppose a pool stores 2,000,000 raw units of a six-decimal token and 1,000,000,000,000,000,000 raw units of an 18-decimal token. Those reserves represent 2 and 1 displayed tokens, not a ratio of two trillion to one. Apply each asset's scale before presenting a human price.

Total supply has the same rule. ERC-20 totalSupply and the SPL mint supply are raw integers. Explorers and analytics services divide by decimals for display. Changing a frontend formatter cannot change supply, and choosing more decimals does not create economic value. It only permits smaller representable fractions and increases the number of base units used for a given displayed supply.

Implementation checklist

Test conversions independently from RPC and UI code. Include values near zero, maximum expected values, and inputs that contain more precision than the token supports.

  • Store network, token address or mint, decimals, and raw amount together at system boundaries.
  • Parse user input from strings into bigint or another exact integer representation.
  • Reject signs, grouping separators, scientific notation, and excess precision unless deliberately supported.
  • Use amountUiString or equivalent string fields for display and raw integers for transactions.
  • Normalize both sides of exchange rates, liquidity reserves, supply, fees, and thresholds.
  • Test zero decimals, six decimals, nine decimals, 18 decimals, very large balances, and one-base-unit transfers.

Scope and limitations

This model covers fungible-token amount scaling. It does not define valuation, acceptable rounding for a particular product, accounting policy, or the behavior of every token extension. Fee-on-transfer, rebasing, interest-bearing, and wrapper tokens can make balance changes differ from a simple requested amount even when decimals are handled correctly. Confirm program-specific semantics before integrating and distinguish displayed accrued values from ledger principal where an extension requires it.

Sources

  1. OpenZeppelin Contracts: ERC20 decimals
  2. Solana Documentation: Tokens on Solana
  3. Solana RPC: getTokenAccountBalance

This article explains technical and market-data concepts. It is not financial, legal, tax, or investment advice. Verify current chain state and primary documentation independently.

Continue researching