Change quote feed
This guide will show you how to fetch the latest feed values for two feeds and convert them to a new quote feed while retaining the number of decimals. For example, if you need the price of BTC/ETH
, you can fetch the latest feed values for BTC/USD
and ETH/USD
and calculate the price of BTC/ETH = (BTC/USD) / (ETH/USD)
.
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol";
/* THIS IS A TEST IMPORT, in production use: import {FtsoV2Interface} from "@flarenetwork/flare-periphery-contracts/coston2/FtsoV2Interface.sol"; */
import {TestFtsoV2Interface} from "@flarenetwork/flare-periphery-contracts/coston2/TestFtsoV2Interface.sol";
/**
* THIS IS AN EXAMPLE CONTRACT.
* DO NOT USE THIS CODE IN PRODUCTION.
*/
contract FtsoV2ChangeQuoteFeed {
TestFtsoV2Interface internal ftsoV2;
/**
* Initializing an instance with FtsoV2Interface.
* The contract registry is used to fetch the contract address.
*/
constructor() {
/* THIS IS A TEST METHOD, in production use: ftsoV2 = ContractRegistry.getFtsoV2(); */
ftsoV2 = ContractRegistry.getTestFtsoV2();
}
/**
* @dev Internal function to scale the base feed value to match the decimals of the final feed.
*/
function _scaleBaseFeedValue(
uint256 _baseFeedValue,
uint8 _baseFeedDecimals,
uint8 _finalDecimals
) internal pure returns (uint256) {
if (_baseFeedDecimals < _finalDecimals) {
// Scale up if base feed decimals are less than final feed decimals
return
_baseFeedValue *
10 ** uint256(_finalDecimals - _baseFeedDecimals);
} else if (_baseFeedDecimals > _finalDecimals) {
// Scale down if base feed decimals are more than final feed decimals
return
_baseFeedValue /
10 ** uint256(_baseFeedDecimals - _finalDecimals);
} else {
// No scaling needed if decimals are equal
return _baseFeedValue;
}
}
/**
* @dev Function to compute the new quote feed value based on the base and quote feed values.
* @param _baseAndQuoteFeedIds Array containing the IDs of the base and quote feeds.
* @return The computed new quote feed value in the original quote decimals.
*/
function getNewQuoteFeedValue(
bytes21[] calldata _baseAndQuoteFeedIds
) external view returns (uint256) {
require(
_baseAndQuoteFeedIds.length == 2,
"Invalid feed indexes. Please provide exactly two indexes."
);
// Fetch current feeds
(uint256[] memory feedValues, int8[] memory decimals, ) = ftsoV2
.getFeedsById(_baseAndQuoteFeedIds);
// The base feed gets scaled by:
// - comparison with the quote feed
// - being returned in the quote feed decimals
uint8 finalDecimals = 2 * uint8(decimals[1]);
// Scale the base feed value to match the final feed decimals
// Scaling is done all at once for smaller calculation errors
uint256 scaledBaseFeedValue = _scaleBaseFeedValue(
feedValues[0],
uint8(decimals[0]),
finalDecimals
);
// Prevent division by zero
require(feedValues[1] != 0, "Division by zero");
// Compute the new quote feed value
uint256 newQuoteFeedValue = scaledBaseFeedValue / feedValues[1];
return newQuoteFeedValue;
}
/**
* @dev Function to compute the new quote feed value based on the base and quote feed values.
* @param _baseAndQuoteFeedIds Array containing the IDs of the base and quote feeds.
* @param _newQuoteDecimals Number of decimals for the returned value.
* @return The computed new quote feed value in the parameter decimals.
*/
function getNewQuoteFeedValueSetDecimals(
bytes21[] calldata _baseAndQuoteFeedIds,
uint8 _newQuoteDecimals
) public view returns (uint256) {
require(
_baseAndQuoteFeedIds.length == 2,
"Invalid feed indexes. Please provide exactly two indexes."
);
// Fetch current feeds
(uint256[] memory feedValues, int8[] memory decimals, ) = ftsoV2
.getFeedsById(_baseAndQuoteFeedIds);
// The base feed gets scaled by:
// - comparison with the quote feed
// - being returned in the "_newQuoteDecimals" decimals
uint8 finalDecimals = uint8(decimals[1]) + _newQuoteDecimals;
// Scale the base feed value to match the final feed decimals
// Scaling is done all at once for smaller calculation errors
uint256 scaledBaseFeedValue = _scaleBaseFeedValue(
feedValues[0],
uint8(decimals[0]),
finalDecimals
);
// Prevent division by zero
require(feedValues[1] != 0, "Division by zero");
// Compute the new quote feed value
uint256 newQuoteFeedValue = scaledBaseFeedValue / feedValues[1];
return newQuoteFeedValue;
}
/**
* @dev Function to compute the new quote feed value based on the base and quote feed values.
* @param _baseAndQuoteFeedIds Array containing the IDs of the base and quote feeds.
* @return The computed new quote feed value in wei (with 18 decimals).
*/
function getNewQuoteFeedValueInWei(
bytes21[] calldata _baseAndQuoteFeedIds
) external view returns (uint256) {
uint256 newQuoteFeedValue = getNewQuoteFeedValueSetDecimals(
_baseAndQuoteFeedIds,
18
);
return newQuoteFeedValue;
}
}
The TestFtsoV2Interface
is for testing only, with all methods as view
to allow rapid development without gas costs or state changes. For production, use FtsoV2Interface
, which includes payable
methods required for real transactions and state modifications.
Make the following changes to FtsoV2ChangeQuoteFeed.sol
:
import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol";
import {FtsoV2Interface} from "@flarenetwork/flare-periphery-contracts/coston2/FtsoV2Interface.sol";
contract FtsoV2ChangeQuoteFeed {
FtsoV2Interface internal ftsoV2;
constructor() {
ftsoV2 = ContractRegistry.getFtsoV2();
}
//...
}
-
Using Remix: Set EVM version to
london
in the Advanced Configurations section of the Solidity Compiler tab: -
Using Hardhat or Foundry: Set EVM version to
london
in hardhat.config.ts or foundry.toml. -
Using Standard Solidity JSON: Set
evmVersion
tolondon
:{
"settings": {
"optimizer": {
/* ... */
},
"evmVersion": "london"
}
} -
Using
solc
CLI: Set--evm-version
tolondon
:solc --evm-version london <args>