Getting FTSO Data Feeds#
This tutorial shows the simplest way to use the FTSO system to retrieve a specific data feed, like the price of Bitcoin.
The tutorial shows:
- How to use the Flare periphery packages to simplify working with the Flare API.
- How to retrieve the latest price for a given asset from the FTSO system.
Code#
Choose your preferred programming language and ensure you have a working development environment.
For easy navigation, numbered comments in the source code link to the tutorial sections below.
GettingDataFeeds.sol | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Building with Hardhat
- Create a new folder and move into it.
- Initialize a new npm project and install dependencies:
If you intend to test as explained in the following steps, be aware that an open issue with Hardhat prevents using versions higher than
npm init npm install hardhat@2.20.1 @nomicfoundation/hardhat-toolbox @flarenetwork/flare-periphery-contracts
2.20.1
. - Create a new Hardhat project (More information in the Hardhat setup guide):
npx hardhat init
- You will not be using the sample project, therefore:
- Remove
contracts/Lock.sol
- Remove
test/Lock.js
- Remove
- Edit
hardhat.config.js
to specify the correct EVM version. Make sure you include the highlighted lines:hardhat.config.jsrequire("@nomicfoundation/hardhat-toolbox"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: { compilers: [{ version: "0.8.17", settings: { evmVersion: "london" }, }], } };
- Copy the Solidity code above into a new file called
GettingDataFeeds.sol
in thecontracts
folder. - Compile with:
npx hardhat compile
Testing with Hardhat
Testing smart contracts before deploying them is typically performed by forking the network or by using mock contracts. These instructions quickly show you how to use the former.
- Build the Hardhat project following the previous instructions.
- Include network information in the
hardhat.config.js
file. Make sure you include the highlighted lines:hardhat.config.jsrequire("@nomicfoundation/hardhat-toolbox"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: { compilers: [{ version: "0.8.17", settings: { evmVersion: "london" }, }], }, networks: { hardhat: { forking: { url: 'https://flare-api.flare.network/ext/bc/C/rpc', }, }, }, };
- Copy the code below into a new file called
TestGettingDataFeeds.js
in thetest
folder.TestGettingDataFeeds.jsconst { expect } = require("chai"); describe("GettingDataFeeds", async function () { let contract; beforeEach(async function () { contract = await ethers.deployContract("GettingDataFeeds"); }); it("Should return sensible values", async function () { const res = await contract.getTokenPriceWei("BTC"); expect(res._timestamp).to.greaterThan(1695817332); expect(res._decimals).to.within(0, 18); expect(res._price).to.within(0, 1000000 * 10 ** Number(res._decimals)); }); });
- Run the test with:
npx hardhat test
Building with Foundry
- If you don't have Foundry installed, follow the instructions for your operating system in the Foundry's Installation guide.
- Create a new Foundry project:
This command creates a new directory called
forge init <PROJECT_NAME>
<PROJECT_NAME>
. Use a name that suits your needs. - Move into the project's directory:
cd <PROJECT_NAME>
- Install dependencies with:
forge install flare-foundation/flare-foundry-periphery-package
- Remove the sample project that Foundry created for you, as you do not need it:
- Remove
src/Counter.sol
- Remove
test/Counter.t.sol
- Remove
- Copy the Solidity code above into a new file called
GettingDataFeeds.sol
in thesrc
folder. - Open the
foundry.toml
file, and add the following lines at the end:evm_version = "london" remappings = [ "@flarenetwork/flare-periphery-contracts/=lib/flare-foundry-periphery-package/src/"]
- Compile with:
forge build
Testing with Foundry
Testing smart contracts before deploying them is typically performed by forking the network or by using mock contracts. These instructions quickly show you how to use the former.
- Build the Foundry project following the previous instructions.
- Copy the code below into a new file called
GettingDataFeeds.t.sol
in thetest
folder.GettingDataFeeds.t.sol// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Import dependencies import "forge-std/Test.sol"; import "../src/GettingDataFeeds.sol"; // Test Contract contract TestGettingDataFeeds is Test { string private constant FLARE_RPC = "https://flare-api.flare.network/ext/bc/C/rpc"; uint256 private flareFork; function setUp() public { flareFork = vm.createFork(FLARE_RPC); } function testSimplePrice() public { vm.selectFork(flareFork); GettingDataFeeds datafeeds = new GettingDataFeeds(); (uint256 _price, uint256 _timestamp, uint256 _decimals) = datafeeds.getTokenPriceWei("BTC"); assertGt(_timestamp, 1695817332, "Timestamp expected to be greater than a known past block"); assertGe(_decimals, 0, "Number of decimals expected to be >= 0"); assertLe(_decimals, 18, "Number of decimals expected to be <= 18"); assertGt(_price, 0, "Price expected to be > 0"); assertLt(_price, 1000000 * 10 ** _decimals, "Price expected to be < 1'000'000"); } }
- Run the test with:
forge test -vv
GettingDataFeeds.js | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Run with Node.js
This tutorial has been tested with npm v9.5 and Node.js v18.16.
- Create a new folder and move into it.
- Copy & paste the code above into a new file called
GettingDataFeeds.js
. - Initialize project and install dependencies with:
npm init npm install ethers@6.3 @flarenetwork/flare-periphery-contract-artifacts@0.1.7
- Run the program with:
node GettingDataFeeds.js
Run in browser
Tutorial#
1. Import Dependencies#
The tutorial uses the following dependencies:
-
The Flare Periphery Package for Solidity and the Flare Periphery Artifacts Package for JavaScript, which provide the API for all Flare smart contracts.
-
If you use JavaScript, the ethers package is also needed to work with smart contracts.
6 7 |
|
8 9 |
|
The Periphery Packages simplify working with the Flare smart contracts significantly. If you remove this dependency, you must manually provide the signatures for all the methods you want to use.
2. Access the Contract Registry#
The FlareContractRegistry
contains the current addresses for all Flare smart contracts, and it is the only recommended way to retrieve them.
Its address is the same on all of Flare's networks, and it is the only Flare address that needs to be hard-coded into any program.
20 21 |
|
15 16 17 18 |
|
3. Retrieve the FTSO Registry#
Prices for all assets tracked by the FTSO system are recovered through the FtsoRegistry
contract.
Use the getContractAddressByName()
method from the FlareContractRegistry
to retrieve the address of the FtsoRegistry
.
24 25 |
|
21 22 23 24 25 26 |
|
This address can be retrieved in the initialization phase of your program and used afterward. There is no need to fetch it every time it must be used.
4. Get Latest Price#
Finally, the asset's price is fetched from the FtsoRegistry
using getCurrentPriceWithDecimals
.
28 29 |
|
29 30 31 32 33 |
|
-
The only parameter of this method is the symbol for the asset being queried, like
"FLR"
or"BTC"
. You can usegetSupportedSymbols()
to retrieve the list of all supported symbols.Warning
On Coston and Coston2, the symbol names are prefixed with "test", such as
"testBTC"
. When you use thegetSupportedSymbols()
function to retrieve the list of supported symbols, the symbol names will already contain the prefix. -
Given that Solidity does not support numbers with decimals, this method returns the requested price as an integer and the number of decimal places by which the comma must be shifted.
For example, if it returns 1234 for the price and 2 for the decimals, the actual price of the asset in USD is 12.34.
-
It also returns the time when the price was calculated by the FTSO system as a UNIX timestamp. You can use an online tool like EpochConverter to turn the timestamp into a human-readable form, or use
Date
as in the JavaScript example.
JavaScript note on overloaded methods
The call to the getCurrentPriceWithDecimals
method is a bit cumbersome in JavaScript:
37 38 |
|
The call needs to be like this because this method is overloaded.
getCurrentPriceWithDecimals
has two versions: one accepting a string for the symbol and another one accepting an integer for the asset's index in the FTSO system.
Therefore, the call needs to disambiguate both versions.
The vast majority of methods are not overloaded and allow a more natural call format. For example:
await ftsoRegistry.getSupportedSymbols();
Conclusion#
This tutorial served as the Hello World program for the FTSO system. It has shown:
- How to use the Flare Periphery Package, both from Solidity and from JavaScript.
- How to retrieve the latest price for a given asset from the FTSO system.