Use this file to discover all available pages before exploring further.
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 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.
For current feeds where decimal = -18 is known and constant:
// Assumes decimal = -18 (all current IFÁ Labs feeds)function toHumanReadable(int256 price) internal pure returns (uint256) { require(price > 0, "Price must be positive"); return uint256(price) / 1e18;}
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.
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:
/// @notice Calculate the USD value of a token amount/// @param tokenAmount Raw token amount (18 decimal places)/// @param oraclePrice Raw price from IFÁ Labs (scaled by 1e18)/// @return usdValue USD value scaled by 1e18function calculateUSDValue( uint256 tokenAmount, int256 oraclePrice) internal pure returns (uint256 usdValue){ require(oraclePrice > 0, "Invalid price"); // Both tokenAmount and oraclePrice are scaled by 1e18 // Multiply then divide to preserve precision usdValue = tokenAmount * uint256(oraclePrice) / 1e18;}
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.
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:
// ✅ Safe cast with guardfunction safeCast(int256 price) internal pure returns (uint256) { require(price > 0, "Price must be positive"); return uint256(price);}// ❌ Unsafe — negative int256 cast to uint256 produces a massive numberuint256 unsafePrice = uint256(price); // wraps if price < 0
For simple display purposes, ethers.formatUnits handles the scaling directly:
const { ethers } = require("ethers");// decimal = -18, so units = 18const humanPrice = ethers.formatUnits(info.price, -info.decimal);console.log(`Price: $${humanPrice}`);// Price: $1.000124
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.
from decimal import Decimal, getcontext# Set high precision for financial calculationsgetcontext().prec = 36def format_price(raw_price: int, decimal: int) -> Decimal: """ Convert a raw IFÁ Labs price to a human-readable Decimal. Args: raw_price: The raw int256 price value from the oracle decimal: The decimal field (negative integer, e.g. -18) Returns: Human-readable price as a Decimal """ if raw_price <= 0: raise ValueError("Price must be positive") if decimal >= 0: raise ValueError("Decimal must be negative") exponent = -decimal # convert -18 to 18 divisor = Decimal(10 ** exponent) return Decimal(raw_price) / divisor# Exampleraw_price = 1000124000000000000decimal = -18price = format_price(raw_price, decimal)print(f"USDT/USD: ${price:.6f}")# USDT/USD: $1.000124
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.
Treating price as a human-readable dollar amount.1000124000000000000 is not 1,000,124,000,000,000,000.Itis1.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.
// ✅ Correct — normalize after multiplicationuint256 result = (valueA * valueB) / 1e18;// ❌ Wrong — result is scaled by 1e36uint256 result = valueA * valueB;