The Flare Time Series Oracle (FTSO) is a smart contract running on the Flare network that provides continuous estimations for different types of data. It does so in a decentralized manner (no single party is in control of the process) and securely (it takes a lot of effort to disrupt the process).
To achieve a secure, decentralized system, a set of independent data providers retrieves data from external sources, like centralized and decentralized exchanges, and supplies the data to the FTSO system. Then, this information is weighted according to each provider's voting power, and a median is calculated to produce the final estimate.
When FTSOs were initially designed, they supported only cryptocurrency price pairs. Now, they support all types of data. However, contract names and methods still refer to prices and price epochs, and price pairs are used in the following information to show how FTSOs work.
The following diagram shows how price pairs are submitted to and filtered by the FTSO system.
Data providers that supply useful information, such as price pairs that are not removed as outliers because they are too far away from the median value, are rewarded, and the resulting data estimates are finally published on-chain.
The following information describes:
- The submission procedure
- How the final estimate is calculated
- How vote delegation works
- How to submit data, claim rewards, and use the data in an app
Using price data as an example, the procedure in the following diagram runs continuously. It produces new data estimates during every Price Epoch, which are 3 minutes long.
Any user with an account (address) on the Flare network can act as an FTSO data provider, submit data, and collect rewards.
During each epoch, only submissions from the 100 data providers with the most voting power are considered. An account's voting power is based on its wrapped
$SGBbalance and the delegations made to it (see Vote Power below).
In this example, submitted data must be the current price (in
$USD) for one or more of the supported price pairs, currently:
$FIL. On Songbird, additionally, you have
More general data types might be added in the future.
FTSO data providers submit data in rounds in a commit-and-reveal process, so they cannot see each other's submissions until a round is over.
This process is like submitting data in a closed envelope, and when the round is over, all envelopes are opened.
During a 3-minute price epoch, providers fetch the information, run their algorithms, and submit a hash of the data (commit). Then, during the first half of the following price epoch (1.5 minutes), providers submit the actual data (reveal).
See technical details about the data-submission process below.
The FTSO system calculates the resulting median, taking into account each provider's voting power (see How Results are Calculated below).
Resulting data is publicly available for 5 price epochs for any app or contract to read. Previous epochs can always be retrieved from an archival node.
For each price epoch in which the submitted data is close enough to the median value, data providers and their delegators are rewarded.
Rewards are accumulated in Reward Epochs (3.5 days on the Flare network, 7 days on Songbird) and can be claimed after the epoch finishes.
See Rewards below.
How Results are Calculated#
The following example uses price pairs to show the filtering process that turns all submitted data into a single estimate. See all details in the Flare whitepaper.
The contract in charge of each price pair calculates the resulting price for a Price Epoch (3 minutes) using the submissions received from all data providers during that epoch.
Each submission has a price and a weight. Weight is based on the data provider's voting power, as explained below.
The weighted median of the prices is the resulting price for the price epoch.
Submissions in the top and bottom 25% range are not rewarded.
As explained above, an FTSO data provider's submissions are weighted by its Vote Power. A data provider's Vote Power is proportional to the amount of Wrapped Flare or Songbird tokens (
$WSGB) it holds, plus any amount delegated to it.
A Vote Power Cap limits the influence of individual data providers to 2.5% of the total Vote Power both on Flare and Songbird.
Any Vote Power above this cap is ignored. If vote power exceeds the limit, consider delegating those
$WSGBto a different data provider.
A snapshot of each data provider's Vote Power is taken once per reward epoch, and the resulting weight is then used throughout the next reward epoch.
The actual snapshot block is called the Voting Power Block and it is randomly chosen from the last blocks of the previous epoch (last 50% on Flare, last 25% on Songbird). It only roughly corresponds to the last 50% or 25% of the time because block production times are not constant.
The first reward epoch on Songbird started on Saturday, 18 September 2021 08:41:39 (GMT), 1631954499 in Unix time and repeats every 7 days. Therefore, all Songbird reward epochs start on Saturday morning (GMT).
The first reward epoch on Flare started on Thursday, 21 July 2022 19:00:05 (GMT), 1658430005 in Unix time and repeats every 3.5 days. Therefore, all Flare reward epochs start on Thursday evening (GMT) and Monday morning (GMT).
$SGB tokens can delegate them to an FTSO data provider to increase its Vote Power and earn a share of its Rewards, resulting in a mutually beneficial arrangement.
Furthermore, delegated tokens are not locked, meaning that they remain in the user's control and the delegation can be removed at any time.
Delegation requires wrapping the native
$SGB into ERC-20
$WSGB tokens, an operation you can reverse at any time.
Due to Vote Power being calculated once per reward epoch, new delegations do not take effect until the following reward epoch.
Moreover, if a change in delegation occurs after the Vote Power Block is sampled (see above), its changes are delayed an extra reward epoch.
Exception: Delegation revocation calls take effect immediately.
Find more details in the Delegation guide.
The easiest way to delegate your tokens is through a supported wallet like Bifrost, or a dapp. Some FTSO data providers have already started providing these dapps as a convenience. Take a look at flaremetrics.io and pick the one you prefer.
For advanced users, Manual Delegation and Claiming below briefly explains how to delegate manually by interacting directly with the FTSO smart contracts.
A percentage of the annual network inflation is reserved to reward FTSO data providers and distributed uniformly among the year's reward epochs (reward epochs are 7-days long on Songbird and 3.5-days long on Flare).
Each reward epoch, rewards are distributed among all data providers whose submission fell within 50% range of the calculated median.
Then, each provider takes a configurable fee (20% by default) and distributes the rest of the reward among all contributors to its Vote Power, i.e. itself and all its delegators, according to the delegated amounts. Find more details in the Delegation guide (Reward Claiming).
FTSO rewards are not automatically transferred to their recipients.
Instead, the amounts are accumulated in the
FtsoRewardManager contract (see System Architecture below) and must be claimed once the reward epoch is finished.
Claiming requires a contract call and therefore a slight gas expenditure. To save on gas costs, multiple reward epochs can be claimed simultaneously. However, be aware that rewards expire after 90 days. Moreover, you probably want to claim soon, to redelegate the received amount and obtain compounded rewards.
It is also worth noting that:
Rewards are paid in the network's native currency (
$FLRon Flare and
Data providers and their delegators must claim independently.
For advanced users, Manual Delegation and Claiming below briefly explains how to claim manually by interacting directly with the FTSO smart contracts.
This section is aimed at developers.
The FTSO system is composed of multiple smart contracts running on the Flare Network.
Using prices as an example, the following diagram shows the flow of data, queries, and rewards through the FTSO system:
The following list describes the most relevant contracts and their purposes:
FTSO: Each data type is handled by its own FTSO contract, including calculation of the filtered feed.
To retrieve information about a data type, access this contract.
If an FTSO contract is redeployed (for example, to fix a bug), its address will change and apps using it will need to be updated. The FTSO Registry contract below tracks this change for you.
You can retrieve the addresses of all FTSO contracts using the
getAllFtsosmethod in the FTSO Registry.
FTSO Registry: Aggregates the output of each individual FTSO contract and provides a convenient one-stop API to retrieve all data.
Price Submitter: This contract is used by the FTSO data providers to submit their data. Although the contract is called
PriceSubmitter, data is not limited to prices.
Reward Manager: Use this contract to claim your rewards, whether you are a data provider or a delegator.
Wrapped Native (WNat): This contract is not exclusively related to the FTSO system, but it is required to wrap and unwrap native tokens into the
$WSGBthat delegation requires.
The Contract Addresses page explains how to securely retrieve each contract's address.
Other contracts, like the FTSO Manager or the FTSO Daemon, are only meant for internal use by the FTSO system.
Manual Delegation and Claiming#
The following information describes the contracts and method calls required to manually delegate and claim FTSO rewards. Find more details in the Delegation guide.
Obtain wrapped tokens
Voting power is delegated to a data provider using wrapped tokens (
WSGB) whereas the native tokens are
One wrapped token can be obtained for each native token without cost, except gas fees, using the
depositmethod. Tokens get locked inside the
WNatcontract and cannot be used until they are unwrapped.
Wrapped tokens can be unwrapped back to native tokens at any time using the
Wrapped tokens adhere to the ERC-20 standard, besides
function deposit() public payable override;
function withdraw(uint256 amount) external override;
Choose the percentage of the total wrapped tokens you want to delegate to 1 - 2 data providers. If the wrapped-token balance changes later, the delegated amounts are automatically adjusted.
Delegation is done through the
WNatcontract too, using the
function delegate(address _to, uint256 _bips) external;
You need to provide the address (
_to) of the chosen data provider and the percentage (
_bips) of the total wrapped amount you want to delegate in bips (hundredths of 1%, so 100% is 10’000 bips).
After a successful invocation of this method, delegation is complete. The following reward epoch will take the newly delegated tokens into account when computing your selected data provider's weight. If the data provider submits useful data and garners any rewards, you will be able to claim your share once the reward epoch is over.
FTSO rewards are claimed using the
claimRewardmethod of the
function claimReward( address payable _recipient, uint256 memory _rewardEpochs ) external returns ( uint256 _rewardAmount );
This call must be made from the address that earned the rewards, but they can be sent to a different recipient, hence the
Rewards can be claimed for several epochs at once so
_rewardEpochsspecifies the list of epochs to claim for. To get the list of epochs with pending rewards, you can use the
Moreover, the claimed reward is typically redelegated, which involves wrapping the received
$SGB. For convenience, you can use the
claimAndWrapRewardmethod on Flare to claim and wrap in one call.
For security reasons, the
FtsoRewardManagercontract contains a limited amount of tokens and is replenished periodically. Sometimes, all delegators claim their rewards in a short period of time immediately after the reward epoch ends, and the contract becomes empty. If you are unable to claim your rewards because the contract is empty, please try again the next day.
Data submission uses a commit-and-reveal scheme to prevent providers from viewing each other's submissions until a round is over. To speed up the process, both phases are actually overlapped so:
All Commit phases happen continuously in so-called 3-minute Price Epochs.
Reveal phases happen during the first half (first 90 seconds) of the following Commit phase.
The published price information is therefore updated every 3 minutes.
Only a hash of the data is submitted during the Commit phase. Next, in the Reveal phase the actual data is sent. If its hash does not match the previous commitment, the data is discarded.
The submission API is slightly different for the Flare and Songbird networks:
FTSO data providers submit data through the PriceSubmitter contract.
Commit: A single hash is needed for each submission.
function submitHash( uint256 _epochId, bytes32 _hash ) external;
Reveal: After all data is submitted, a single random number must be submitted.
function revealPrices( uint256 _epochId, uint256 memory _ftsoIndices, uint256 memory _prices, uint256 _random ) external;
FTSO data providers submit data through the PriceSubmitter contract.
Commit: A separate hash is needed for each submission.
function submitPriceHashes( uint256 _epochId, uint256 memory _ftsoIndices, bytes32 memory _hashes ) external;
Reveal: Along with each data submission, a random number must be submitted too.
function revealPrices( uint256 _epochId, uint256 memory _ftsoIndices, uint256 memory _prices, uint256 memory _randoms ) external;
Data produced by the FTSO is publicly available on the Flare and Songbird networks.
All data can be retrieved either through the
FtsoRegistry contract or directly through one of the
In any case, the
getCurrentPrice method is used. The following examples show how this method is used to retrieve price data.
function getCurrentPrice( uint256 _ftsoIndex ) external view returns ( uint256 _price, uint256 _timestamp );
_ftsoIndex is one of the allowed indices returned by
getSupportedIndices, for example.
function getCurrentPrice( string memory _symbol ) external view returns ( uint256 _price, uint256 _timestamp );
_symbol is one of the allowed symbols returned by
getSupportedSymbols, for example.
First you need to obtain the address of the
Ftso contract managing the price pair you are interested in.
You can use
getSupportedIndicesSymbolsAndFtsos from the
FtsoRegistry, for example.
getCurrentPrice on the FTSO directly:
function getCurrentPrice( ) external view returns ( uint256 _price, uint256 _timestamp );
Individual FTSO contracts might be updated periodically, which will change their addresses. Instead of caching these addresses, use the
GetCurrentPrice returns the requested price (the outcome of the previous 3-minute price epoch) in
$USD multiplied by 100'000.
For example, a return value of
2603 means a price of
0.02603 USD (There are only 5 significant decimal places).
A standard Unix timestamp of the last price update is also returned.