How to Use IFA Oracle Price Feed in EVM Contracts

This guide explains how to integrate IFA Oracle price feeds into your EVM contracts for accessing real-time stablecoin and asset price data. IFA Oracle provides decentralized price feeds specialized for stablecoins and other assets with high precision calculations.


Install IFA Price Feed Interface

IFA Oracle provides a Solidity interface package to interact with the deployed price feed contracts.

Truffle/Hardhat

If you are using Truffle or Hardhat, simply install the NPM package:

npm install ifapricefeed-interface

Foundary

If you are using Foundry, you will need to create an NPM project if you don't already have one. From the root directory of your project, run:

npm init -y
npm install ifapricefeed-interface

Then add the following line to your remappings.txt file:

ifapricefeed-interface/=node_modules/ifapricefeed-interface

Contract Addresses and Asset Registry

Write Contract Code

The code snippet below provides a general template for integrating IFA Oracle price feeds:

pragma solidity ^0.8.29;
 
import "ifapricefeed-interface/IIfaPriceFeed.sol";
 
contract MyContract {
    IIfaPriceFeed public immutable ifaPriceFeed;
 
    /**
     * @param ifaPriceFeedAddress The address of the IFA Price Feed contract
     */
    constructor(address ifaPriceFeedAddress) {
        // The IIfaPriceFeed interface from ifapricefeed-interface provides the methods to interact with the IFA Oracle contract.
        // Instantiate it with the IFA Oracle contract address from the deployment addresses above
        ifaPriceFeed = IIfaPriceFeed(ifaPriceFeedAddress);
    }
 
    /**
     * This method demonstrates how to interact with the IFA Oracle contract.
     * Select the Asset IDs for the assets you want to fetch prices for.
     * See the complete list of supported assets and their IDs in our Asset Registry.
     */
    function getAssetPrice() public view returns (
        IIfaPriceFeed.PriceFeed memory assetInfo,
        bool exists
    ) {
        // Replace with actual Asset ID from the Asset Registry
        bytes32 assetIndex = 0x0000000000000000000000000000000000000000000000000000000000000000;
        return ifaPriceFeed.getAssetInfo(assetIndex);
    }
 
    /**
     * Example: Get exchange rate between two assets
     * The derived pair price has 30 decimal precision (scaled by 10^30)
     */
    function getExchangeRate() public view returns (IIfaPriceFeed.DerviedPair memory pairInfo) {
        bytes32 fromIndex = 0x0000000000000000000000000000000000000000000000000000000000000000;
        bytes32 toIndex = 0x1111111111111111111111111111111111111111111111111111111111111111;
        
        return ifaPriceFeed.getPairbyId(
            fromIndex,
            toIndex,
            IIfaPriceFeed.PairDirection.Forward
        );
    }
 
    /**
     * Example: Convert amount from one asset to another
     * Note: Derived prices have 30 decimal precision for maximum accuracy
     */
    function convertAssets(uint256 amount) public view returns (uint256 convertedAmount) {
        IIfaPriceFeed.DerviedPair memory pair = getExchangeRate();
        
        // The derivedPrice has 30 decimal precision (10^30), adjust accordingly
        convertedAmount = (amount * pair.derivedPrice) / (10 ** 30);
    }
}

The code snippet above demonstrates the following key steps:

  1. Instantiate the IIfaPriceFeed interface from the Solidity interface package using the price feeds contract address.

  2. Select the Asset IDs for the assets you want to fetch prices for. Asset IDs are generated by hashing the asset symbol.

  3. Call IIfaPriceFeed.getAssetInfo to read individual asset price information.

  4. Call IIfaPriceFeed.getPairbyId to calculate exchange rates between two assets.

  5. Handle decimal precision correctly - derived pair prices have 30 decimal places for maximum precision.


Key Concepts

Assets

An asset represents a token's price with respect to USD (e.g., CNGN/USD, BTC/USD). Each asset is identified by a unique hash of its symbol.

Pairs

A pair represents the exchange rate between two assets (e.g., CNGN/BTC). Pairs can be calculated in both forward and backward directions.

Precision

  • Asset prices use their native decimal precision (stored as negative values, e.g., -18 for 18 decimals)

  • Derived pair prices are always scaled by 10^30 for maximum precision


Function Examples

1. Get Single Asset Information

function getAssetExample() external view {
    // Get asset/USD price information
    // Replace with actual Asset ID from the Asset Registry
    bytes32 assetIndex = 0x0000000000000000000000000000000000000000000000000000000000000000;
    (IIfaPriceFeed.PriceFeed memory assetInfo, bool exists) = ifaPriceFeed.getAssetInfo(assetIndex);
    
    if (exists) {
        // assetInfo.price contains the asset/USD price
        // assetInfo.decimal indicates the decimal places (e.g., -18)
        // assetInfo.lastUpdateTime shows when it was last updated
    }
}

2. Get Multiple Assets Information

function getMultipleAssetsExample() external view {
    bytes32[] memory assetIndexes = new bytes32[](3);
    assetIndexes[0] = 0x0000000000000000000000000000000000000000000000000000000000000000;
    assetIndexes[1] = 0x1111111111111111111111111111111111111111111111111111111111111111;
    assetIndexes[2] = 0x2222222222222222222222222222222222222222222222222222222222222222;
    
    (
        IIfaPriceFeed.PriceFeed[] memory assetsInfo,
        bool[] memory exists
    ) = ifaPriceFeed.getAssetsInfo(assetIndexes);
    
    // Process each asset's information
    for (uint256 i = 0; i < assetsInfo.length; i++) {
        if (exists[i]) {
            // Process assetsInfo[i] - each price has its native decimal precision
        }
    }
}

3. Get Single Pair Exchange Rate

function getSinglePairExample() external view {
    bytes32 asset0Index = 0x0000000000000000000000000000000000000000000000000000000000000000;
    bytes32 asset1Index = 0x1111111111111111111111111111111111111111111111111111111111111111;
    
    // Get asset0/asset1 rate
    IIfaPriceFeed.DerviedPair memory pair = ifaPriceFeed.getPairbyId(
        asset0Index,
        asset1Index,
        IIfaPriceFeed.PairDirection.Forward
    );
    
    // pair.derivedPrice contains the exchange rate with 30 decimal precision (scaled by 10^30)
    // pair.decimal is always -30, indicating 30 decimal places
    // pair.lastUpdateTime is the minimum of both assets' update times
}

4. Get Multiple Pairs (Forward Direction)

function getMultiplePairsForwardExample() external view {
    bytes32[] memory assets0 = new bytes32[](2);
    bytes32[] memory assets1 = new bytes32[](2);
    
    assets0[0] = 0x0000000000000000000000000000000000000000000000000000000000000000;
    assets0[1] = 0x1111111111111111111111111111111111111111111111111111111111111111;
    assets1[0] = 0x2222222222222222222222222222222222222222222222222222222222222222;
    assets1[1] = 0x3333333333333333333333333333333333333333333333333333333333333333;
    
    IIfaPriceFeed.DerviedPair[] memory pairs = ifaPriceFeed.getPairsbyIdForward(
        assets0,
        assets1
    );
    
    // Returns [asset0[0]/asset1[0], asset0[1]/asset1[1]]
    // Each pair.derivedPrice has 30 decimal precision (scaled by 10^30)
}

5. Get Multiple Pairs (Backward Direction)

function getMultiplePairsBackwardExample() external view {
    bytes32[] memory assets0 = new bytes32[](2);
    bytes32[] memory assets1 = new bytes32[](2);
    
    assets0[0] = 0x0000000000000000000000000000000000000000000000000000000000000000;
    assets0[1] = 0x1111111111111111111111111111111111111111111111111111111111111111;
    assets1[0] = 0x2222222222222222222222222222222222222222222222222222222222222222;
    assets1[1] = 0x3333333333333333333333333333333333333333333333333333333333333333;
    
    IIfaPriceFeed.DerviedPair[] memory pairs = ifaPriceFeed.getPairsbyIdBackward(
        assets0,
        assets1
    );
    
    // Returns [asset1[0]/asset0[0], asset1[1]/asset0[1]]
    // Each pair.derivedPrice has 30 decimal precision (scaled by 10^30)
}

6. Get Multiple Pairs with Custom Directions

function getMultiplePairsCustomDirectionExample() external view {
    bytes32[] memory assets0 = new bytes32[](2);
    bytes32[] memory assets1 = new bytes32[](2);
    IIfaPriceFeed.PairDirection[] memory directions = new IIfaPriceFeed.PairDirection[](2);
    
    assets0[0] = 0x0000000000000000000000000000000000000000000000000000000000000000;
    assets1[0] = 0x1111111111111111111111111111111111111111111111111111111111111111;
    directions[0] = IIfaPriceFeed.PairDirection.Forward; // asset0[0]/asset1[0]
    
    assets0[1] = 0x2222222222222222222222222222222222222222222222222222222222222222;
    assets1[1] = 0x3333333333333333333333333333333333333333333333333333333333333333;
    directions[1] = IIfaPriceFeed.PairDirection.Backward; // asset1[1]/asset0[1]
    
    IIfaPriceFeed.DerviedPair[] memory pairs = ifaPriceFeed.getPairsbyId(
        assets0,
        assets1,
        directions
    );
    
    // Returns pairs based on specified directions, each with 30 decimal precision
}

Example of Real-World Use Cases

1. Stablecoin Swap Contract

contract StablecoinSwap {
    IIfaPriceFeed public immutable priceFeed;
    
    constructor(address _priceFeedAddress) {
        priceFeed = IIfaPriceFeed(_priceFeedAddress);
    }
    
    function swap(
        address fromToken,
        address toToken,
        uint256 amount
    ) external {
        // Get exchange rate using Asset IDs
        bytes32 fromAssetId = 0x0000000000000000000000000000000000000000000000000000000000000000;
        bytes32 toAssetId = 0x1111111111111111111111111111111111111111111111111111111111111111;
        
        IIfaPriceFeed.DerviedPair memory pair = priceFeed.getPairbyId(
            fromAssetId,
            toAssetId,
            IIfaPriceFeed.PairDirection.Forward
        );
        
        // Calculate output amount (accounting for 10^30 scaling)
        uint256 outputAmount = (amount * pair.derivedPrice) / (10 ** 30);
        
        // Perform token transfers
        IERC20(fromToken).transferFrom(msg.sender, address(this), amount);
        IERC20(toToken).transfer(msg.sender, outputAmount);
    }
}

2. Price Validation Contract

contract PriceValidator {
    IIfaPriceFeed public immutable priceFeed;
    uint256 public constant MAX_PRICE_AGE = 300; // 5 minutes
    
    constructor(address _priceFeedAddress) {
        priceFeed = IIfaPriceFeed(_priceFeedAddress);
    }
    
    function validateAssetPrice() external view returns (bool isValid) {
        bytes32 assetIndex = 0x0000000000000000000000000000000000000000000000000000000000000000;
        (IIfaPriceFeed.PriceFeed memory asset, bool exists) = priceFeed.getAssetInfo(assetIndex);
        
        return exists && 
               asset.price > 0 && 
               (block.timestamp - asset.lastUpdateTime) <= MAX_PRICE_AGE;
    }
}

Data Structures

PriceFeed

struct PriceFeed {
    int8 decimal;           // Decimal places (most asset have  10^18 scaling) (negative value, e.g., -18)
    uint256 lastUpdateTime; // Timestamp of last update
    int256 price;          // Price value scaled by decimal places
}

DerviedPair

struct DerviedPair {
    int8 decimal;           // Always -30 (indicating 10^30 scaling)
    uint256 lastUpdateTime; // Minimum timestamp of both assets
    uint256 derivedPrice;   // Exchange rate scaled by 10^30
}

PairDirection

enum PairDirection {
    Forward,  // asset0/asset1
    Backward  // asset1/asset0
}

Error Handling

The IFA Price Feed system includes comprehensive error handling:

function safeGetPair() external view returns (IIfaPriceFeed.DerviedPair memory pair, bool success) {
    bytes32 asset0 = 0x0000000000000000000000000000000000000000000000000000000000000000;
    bytes32 asset1 = 0x1111111111111111111111111111111111111111111111111111111111111111;
    
    try ifaPriceFeed.getPairbyId(
        asset0,
        asset1,
        IIfaPriceFeed.PairDirection.Forward
    ) returns (IIfaPriceFeed.DerviedPair memory result) {
        return (result, true);
    } catch {
        return (pair, false); // Return empty pair with success = false
    }
}

Best Practices

  1. Always check asset existence before using price data

  2. Validate price freshness by checking lastUpdateTime

  3. Handle the 10^30 scaling correctly for derived pairs

  4. Use batch functions for multiple assets to save gas

  5. Implement proper error handling for failed price lookups


Common Asset Symbols

Replace the placeholder Asset IDs (0x0000..., 0x1111..., etc.) in the examples above with actual Asset IDs from our supported assets:

  • CNGN - Nigerian Naira stablecoin

  • USDT - USD Stablecoin (by Tether)

  • USDC - USD Stablecoin (by circle)

  • EURC - Euro Stablecoin

  • BTC - Bitcoin

  • ETH - Ethereum

  • And many more...

For the complete list of supported assets and their corresponding Asset IDs, see our Asset Registry.


Additional Resources


Support

For technical support and integration assistance, please refer to the IFA Labs documentation or contact the development team here

Last updated