Skip to content

Research notes

Morpho Oracle Prices: Apply the Decimal Scaling

Rebuild an 18-to-6-decimal collateral valuation, expose a trillion-fold scale error and preserve Blue's separate valuation, LLTV and debt rounding.

Ivory ceramic rails with different tooth spacing joined by a lime sleeve on a black surface.
Illustration for research notes; examples in this article are educational.

Morpho Blue's price() returns a rate between token base units, scaled by 10^36. In the core health check, multiply raw collateral by that price, divide by 10^36 and round down to loan-token base units. For a human quote, divide price() by ten raised to the exponent (36 + loan-token decimals − collateral-token decimals). An 18-decimal collateral and six-decimal loan token therefore use a 24-decimal quote scale.

A very large oracle integer can be correctly scaled. The useful check is whether it reproduces the value of a known collateral quantity in the market's loan token. A screen that divides every Blue oracle answer by 10^36 can pass its contract read while showing the wrong exchange rate.

Identify the collateral and loan units first

This article follows the variable-rate Blue core at v1.0.0, commit 55d2d99304fb. Morpho's current Blue contract reference identifies each market through five parameters: loan token, collateral token, oracle, interest-rate model and liquidation loan-to-value limit (LLTV). Vault V1/V2 accounting and Midnight fixed-rate contracts require their own implementation analysis. The pin here does not identify a particular live deployment.

Call the collateral token C and the loan token L. A base unit is one unit of the raw token integer. If C has 18 decimals, one C contains 10^18 base units. If L has six decimals, one L contains 10^6 base units. The ERC-20 amount guide explains the token metadata behind those display scales.

QuantityUnit or purpose
Raw collateral amountC base units
Oracle output PL base units per C base unit, multiplied by 10^36
Oracle normalization constant10^36
Collateral value after normalizationL base units
Human collateral valueWhole L, after applying L's decimals

The pinned IOracle interface specifies this pair-dependent interpretation. The core's ConstantsLib separately fixes ORACLE_PRICE_SCALE at 10^36. Different token decimals change how P represents a human quote; they do not change that core constant.

Derive the human quote from the raw-unit rate

Let q mean whole L per whole C. Let dC and dL be the collateral and loan decimal counts. One C base unit is 10 raised to negative dC whole C. Its value is therefore q multiplied by that quantity, expressed in whole L. Converting those L into base units adds a factor of 10^dL.

Consequently, the base-unit exchange rate is q multiplied by 10 raised to dL minus dC. P stores that rate multiplied by another 10^36. To recover q, divide P by ten raised to the combined exponent:

Human-quote exponent = 36 + dL − dC.

Morpho's oracle contract documentation gives the same precision relationship. For ordinary pairs in the following table, the divisor is a positive integer power of ten.

C decimalsL decimalsDivide P by this for whole L per whole C
18610^24
8610^34
6610^36
61810^48

The first row needs twelve fewer human-quote places because the collateral's 18-place scale exceeds the loan token's six-place scale by twelve. That adjustment is already represented in P. Applying another collateral-to-loan decimal correction during raw collateral valuation would repeat the adjustment.

For unusual decimal combinations, treat the exponent algebraically and check the selected oracle's construction and integer range. Do not turn this table into an assumption that every ERC-20 decimal configuration is supported by every adapter.

Reconstruct an 18-to-6 valuation exactly

The following example is entirely hypothetical. C and L are fictional ordinary tokens, and none of the inputs is a live Morpho quote. Assume C has 18 decimals, L has six, and the selected oracle correctly represents a rate of 3,125.75 L per C.

For this pair, P equals 3,125.75 multiplied by 10^24. Its exact integer is 3125750000000000000000000000. This preserves both the human rate and the difference between the token units.

Assume a position has 1234567890123456789 C base units, representing exactly 1.234567890123456789 C. Reconstruct its collateral valuation in this order:

  1. Multiply that raw collateral integer by P, keeping the product exact.
  2. Divide the product by 10^36, rounding down for the health-check valuation.
  3. Format the resulting L base units with L's six decimals.
ResultExact value
Collateral quantity1.234567890123456789 C
Human exchange rate3,125.75 L/C
Value before raw-unit rounding3,858.95058255339505821675 L
Value rounded down to L base units3,858,950,582
Human value of that integer3,858.950582 L

The division discards 0.55339505821675 of one L base unit, equivalent to 0.00000055339505821675 L. This is a numerical rounding difference. The collateral quantity remains unchanged, and no token sale has occurred.

The unit cancellation is the reason the procedure works: C base units multiplied by a scaled L-base-unit-per-C-base-unit rate leave scaled L base units. Dividing by 10^36 removes that rate scale. Only the final display conversion uses L's six decimals.

Use exact integer arithmetic for this reconstruction. The pinned MathLib multiplies before dividing in mulDivDown. Its Solidity multiplication also needs to fit uint256; an off-chain arbitrary-precision result alone does not establish that every proposed input fits the contract's arithmetic.

Locate a scale error before adjusting the answer

Dividing this P by 10^36 yields 0.00000000312575. That number describes L base units per C base unit. Labeling it “L per C” makes the human quote one trillion times too small.

Multiplying the human collateral quantity by that mislabeled rate produces 0.00000000385895058255339505821675 L. The correct unrounded value is 3,858.95058255339505821675 L. The factor between them is exactly 10^12, matching the twelve-place difference between the token decimals.

Other shortcuts fail differently. Integer-dividing P by 10^36 before multiplication gives zero for this fixture. Integer-dividing the collateral amount by 10^18 first leaves only one C and loses the fractional holding. Display formatting should happen after the exact valuation path has preserved those fractions.

Check the price and quantity independently. For one whole C, the raw valuation must produce 3,125,750,000 L base units, displayed as 3,125.75 L. For one C base unit, the exact value is only 0.00000000000000312575 L; downward conversion to L base units produces zero. That zero is expected dust rounding, while zero for the full position identifies a broken calculation.

An Aave scaled aToken balance involves a separate income-index conversion. Blue's P is a collateral-to-loan rate. Importing Aave's 10^27 ray scale would introduce a different quantity into this worksheet.

Apply LLTV and debt conversion after valuation

The pinned Blue health check first rounds collateral valuation down, then multiplies that integer by LLTV and rounds down again using WAD, or 10^18. It compares the resulting maximum debt with upward-rounded debt assets. Equality passes this comparison.

Add an illustrative LLTV of 80%, encoded as 800000000000000000. Multiplying the example's 3,858,950,582 L base units by 0.8 gives 3,087,160,465.6. The second downward rounding leaves 3,087,160,465 L base units, or 3,087.160465 L. Keep this separate from the collateral value above.

Carrying the unrounded collateral value into the LLTV multiplication and rounding only once would instead yield 3,087,160,466 L base units. That is one base unit more. Reproduce the core's two divisions separately when checking a boundary; combining them changes this fixture's result.

Debt needs its own conversion. In SharesMathLib, VIRTUAL_ASSETS is 1 and VIRTUAL_SHARES is 10^6. For borrow shares B, multiply B by totalBorrowAssets plus 1, divide by totalBorrowShares plus 10^6, and round up. The virtual-share constant is independent of L's decimal count.

For example, stipulate totalBorrowAssets of 5,000,000,000 L base units, totalBorrowShares of 5,000,000,000,000,000 internal shares and B of 3,000,000,000,000,001 internal shares. That conversion gives debt of 3,000,000,001 L base units, displayed as 3,000.000001 L. This is below the illustrative maximum debt. All totals must represent the appropriate accrued state; Morpho's market mechanics reference distinguishes stored asset totals from shares.

The broader LTV versus liquidation-threshold guide uses an Aave-style model with separate borrowing parameters. For this Blue calculation, use the actual market's LLTV and integer comparison. The Blue LLTV and liquidation-incentive guide follows what the liquidation parameters mean after valuation. A healthy comparison also does not establish available cash; Blue withdrawal liquidity versus supply examines that separate market constraint.

Validate the oracle boundary and preserve the snapshot

A component feed can have its own decimals. An adapter may combine several feeds or a wrapper exchange rate before returning P. The Chainlink feed-versus-token-decimals guide covers those upstream units. Once reading the market oracle's final price(), interpret its output under IOracle's convention. Do not divide that output by a component feed's precision again.

Morpho is oracle agnostic. The shared interface defines the returned unit but does not certify the underlying price. IOracle exposes no timestamp or round identifier, so checking freshness requires examining the selected implementation and its dependencies. The official oracle inspection guide shows how feed paths, administrators and fixed 1:1 assumptions can matter. A correct decimal calculation can still reproduce an economically unsuitable oracle result.

Retain a record that another reader can reconstruct:

Snapshot fieldValidation
Chain, Blue contract and market IDRecover all five market parameters
Collateral and loan contractsEstablish both token identities and decimal counts
Oracle address and implementationConfirm the selected price path and assumptions
Block reference and PBind the raw output to the position observation
Raw collateral and valuationReproduce multiplication, division and remainder
LLTV and accrued debt inputsPreserve both rounding stages and virtual constants

Exercise the record with one whole collateral token, one base unit and the full position. Require the first to reconstruct the human quote, explain dust rounding in the second, and reproduce the loan-base-unit integer in the third. Save those exact results before rounding anything for a screen.

Keep the context with the example.

Each worked example is illustrative, with its sources and assumptions in the article. Read our editorial standards for authorship, verification and corrections.