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
Asset Registry: Complete list of supported assets and their IDs
Contract Addresses: Deployment addresses for all networks
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:
Instantiate the IIfaPriceFeed interface from the Solidity interface package using the price feeds contract address.
Select the Asset IDs for the assets you want to fetch prices for. Asset IDs are generated by hashing the asset symbol.
Call IIfaPriceFeed.getAssetInfo to read individual asset price information.
Call IIfaPriceFeed.getPairbyId to calculate exchange rates between two assets.
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
Always check asset existence before using price data
Validate price freshness by checking
lastUpdateTime
Handle the 10^30 scaling correctly for derived pairs
Use batch functions for multiple assets to save gas
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 stablecoinUSDT
- USD Stablecoin (by Tether)USDC
- USD Stablecoin (by circle)EURC
- Euro StablecoinBTC
- BitcoinETH
- EthereumAnd many more...
For the complete list of supported assets and their corresponding Asset IDs, see our Asset Registry.
Additional Resources
Asset Registry: Complete list of supported assets and their IDs
Contract Addresses: Deployment addresses for all networks
Interface Package:
npm install ifapricefeed-interface
Support
For technical support and integration assistance, please refer to the IFA Labs documentation or contact the development team here
Last updated