Skip to main content
IFÁ Labs price reads are already among the cheapest external calls you can make in a Solidity contract — getAssetInfo is a pure storage read with no computation overhead. But in protocols that read prices frequently, across multiple assets, or inside functions called thousands of times, small inefficiencies compound into real costs. This page covers every meaningful optimization available for oracle integrations, ordered from highest to lowest impact.

1. Declare Constants at Compile Time

The single highest-impact optimization. Declaring the oracle address and all asset IDs as constant eliminates every runtime lookup and computation associated with them.
Impact: A cold SLOAD costs 2,100 gas. A constant costs 0. On a protocol processing thousands of transactions per day, this difference is significant.

2. Batch Multiple Price Reads

If your contract needs more than one price in the same transaction, always use getAssetsInfo instead of multiple getAssetInfo calls. One external call is cheaper than N external calls by a wide margin.
Impact: Each external call carries a fixed 100 gas base cost plus the call overhead. For three assets, batching saves roughly 200–400 gas per transaction before accounting for calldata differences.

3. Cache Prices for Repeated Access Within a Transaction

If your contract reads the same price multiple times within a single transaction — across different internal functions — read it once and pass it as a parameter rather than calling the oracle repeatedly.

4. Cache Prices Across Transactions (When Appropriate)

For protocols where the same price is consumed many times per block or across short time windows, storing the last read price in contract storage avoids repeated oracle calls entirely.
Only cache prices for operations where a slightly stale value is acceptable. Never use a cached price for liquidation logic, collateral valuation, or any function where financial correctness depends on the most current available data.

5. Pack Storage Structs Efficiently

When storing oracle-related data in your own contract’s storage, pack smaller types into single 32-byte slots to minimise SSTORE and SLOAD costs.
Impact: The efficient struct uses 2 storage slots instead of 3 — a 33% reduction in storage costs for every read and write.

6. Avoid Oracle Reads in Loops

Reading from the oracle inside a loop is an expensive pattern that scales linearly with iteration count. Pull prices out of loops wherever possible.
If positions reference different assets, fetch all required prices via getAssetsInfo before entering the loop rather than calling getAssetInfo individually on each iteration.

7. Use immutable for Constructor-Set Addresses

If the oracle address needs to be set at deployment time rather than hardcoded as a constant — for example, to support different addresses across test and production deployments via a deploy script — use immutable instead of a storage variable.
immutable variables are embedded directly in the contract bytecode at deployment. Reading them costs the same as a constant — zero storage access — while giving you deployment-time flexibility.

Gas Cost Reference

A practical reference for the operations discussed on this page:
All gas figures are approximate and based on current EVM opcode pricing. Actual costs depend on the specific execution context, compiler version, and optimiser settings. Always benchmark with Foundry’s gas reporter or Hardhat’s gas reporter plugin against your actual contract before drawing conclusions.

Optimisation Checklist

Before deploying any contract that consumes IFÁ Labs price feeds, run through this list:
1

Constants declared

Oracle address and all asset IDs are constant or immutable. No runtime keccak256 calls. No storage variables for the oracle address.
2

Batch reads used

Any function that needs more than one price uses getAssetsInfo. No consecutive getAssetInfo calls for different assets in the same function.
3

No oracle reads in loops

Prices are fetched before loops, not inside them. For multi-asset loops, all prices are pre-fetched via getAssetsInfo.
4

Structs packed

Any custom structs storing oracle data use the smallest appropriate types (uint64 for timestamps, int8 for decimals) and are ordered to minimise slot usage.
5

Caching evaluated

If the same price is read multiple times in a transaction, it’s fetched once and passed as a parameter. Cross-transaction caching is only used for non-critical paths.
6

Gas benchmarked

Integration has been tested with a gas reporter tool and costs are within acceptable bounds for the protocol’s expected transaction volume.

Next Steps

Complete Example Contract

See all patterns — reads, verification, batching, and gas optimisation — combined in a single production-ready contract.

Core Concepts

Understand the oracle mechanics behind the price data your contracts consume.