Skip to main content
IFÁ Labs stores prices on-chain as scaled integers. Solidity does not support floating-point arithmetic, so decimal values like $1.000124 are represented as large integers with a separate scaling exponent. Understanding this representation is essential for reading prices correctly — a single formatting error turns $1.00 into $1,000,000,000,000,000,000. This page covers the scaling model, how to convert prices in every relevant language and environment, and the edge cases worth knowing before you go to production.

The Scaling Model

Every price returned by getAssetInfo consists of two fields that work together: The conversion formula:
Example — USDT at $1.000124:
Example — CNGN at $0.000613:

Why Negative Decimals

The decimal field uses a negative exponent convention — -18 means “divide by 10^18”, not “multiply by 10^(-18)”. This is a deliberate design choice that aligns with common EVM fixed-point conventions:
  • decimal = -18 → divide by 1e18 → 18 decimal places of precision
  • decimal = -8 → divide by 1e8 → 8 decimal places of precision
  • decimal = -6 → divide by 1e6 → 6 decimal places of precision
All current IFÁ Labs stablecoin feeds use decimal = -18. ETH/USD also uses decimal = -18. This is unlikely to change for existing feeds, but always read decimal dynamically rather than hardcoding 18 — future feeds for assets with different precision requirements may use different values.

Converting Prices in Solidity

Fixed Decimal (Production Pattern)

For current feeds where decimal = -18 is known and constant:
Limitation: This returns an integer — $1.000124 becomes 1, not 1000124000000000000. For display or integer math where full precision isn’t needed, this is fine. For precise financial calculations, use the raw price value directly without converting.

Dynamic Decimal (Future-Proof Pattern)

For protocols that want to handle any decimal value without hardcoding:

Preserving Precision in Fixed-Point Math

If your protocol does financial calculations with oracle prices — collateral valuation, liquidation ratios, fee computation — do not convert to human-readable format first. Work with the raw scaled integer to preserve full precision:
Never divide first and then multiply. Integer division truncates remainders — dividing first loses precision that cannot be recovered. Always multiply before dividing in fixed-point arithmetic.

Safe int256 to uint256 Casting

The price field is typed as int256 to allow for future flexibility. All current feeds return positive values, but always guard against the zero and negative cases:

Converting Prices in JavaScript

Basic Conversion with ethers.js


Using ethers formatUnits

For simple display purposes, ethers.formatUnits handles the scaling directly:
ethers.formatUnits expects a positive integer for the units argument. Pass -info.decimal (negating the negative decimal value) to get the correct exponent. For decimal = -18, this gives 18.

High-Precision JavaScript with BigInt

For financial applications where floating-point rounding is unacceptable:

Converting Prices in Python

Basic Conversion


Web3.py Integration


Precision Reference

For all current IFÁ Labs feeds: All current feeds use 18 decimal places. Always read the decimal field dynamically in production code — hardcoding 18 will break if a future asset uses a different precision.

Common Mistakes

Treating price as a human-readable dollar amount. 1000124000000000000 is not 1,000,124,000,000,000,000.Itis1,000,124,000,000,000,000. It is 1.000124. Always apply the decimal scaling before displaying or using the value. Dividing by a hardcoded constant without reading decimal. If you hardcode / 1e18 and a future feed uses decimal = -8, your conversion will be wrong by a factor of 10^10. Read decimal from the struct. Floating-point arithmetic for financial calculations. JavaScript’s Number type has 53 bits of precision. 1000124000000000000 exceeds the safe integer range — use BigInt in JavaScript and Decimal in Python for any calculations involving raw oracle prices. Multiplying two scaled values without normalizing. If both values are scaled by 1e18, multiplying them produces a result scaled by 1e36. You must divide by 1e18 after multiplying to return to 1e18 scale.

Next Steps

Contract Addresses

Full reference for all deployed oracle contract addresses.

Function Reference

Complete API reference for all oracle contract functions.