From 62f016a518ff1e8c6141a9cffff4a51de3784fe5 Mon Sep 17 00:00:00 2001 From: dineshpinto Date: Thu, 6 Jun 2024 03:47:19 +0400 Subject: [PATCH] General cleanup --- .../FtsoV2ChangeQuoteFeed.sol | 68 ++++++++--------- .../FtsoV2FeedConsumer.sol | 6 +- docs/2-network.mdx | 10 +-- docs/ftso/0-overview.mdx | 4 +- docs/ftso/1-getting-started.mdx | 8 +- docs/ftso/2-feeds.mdx | 4 +- docs/ftso/guides/change-quote-feed.mdx | 73 ++++++++++--------- docs/ftso/guides/read-feeds-offchain.mdx | 2 +- guides/2024-06-03-deploy-first-contract.mdx | 41 ++++++++++- guides/tags.yml | 3 + 10 files changed, 126 insertions(+), 93 deletions(-) diff --git a/code_examples/developer-hub-solidity/FtsoV2ChangeQuoteFeed.sol b/code_examples/developer-hub-solidity/FtsoV2ChangeQuoteFeed.sol index d917b51c..1ac2764e 100644 --- a/code_examples/developer-hub-solidity/FtsoV2ChangeQuoteFeed.sol +++ b/code_examples/developer-hub-solidity/FtsoV2ChangeQuoteFeed.sol @@ -7,17 +7,9 @@ interface IFastUpdater { ) external view - returns ( - uint256[] memory _feedValues, - int8[] memory _decimals, - uint64 _timestamp - ); + returns (uint256[] memory _feedValues, int8[] memory _decimals, int64 _timestamp); } -/** - * THIS IS AN EXAMPLE CONTRACT. - * DO NOT USE THIS CODE IN PRODUCTION. - */ contract FtsoV2ChangeQuoteFeed { IFastUpdater internal ftsoV2; @@ -30,54 +22,54 @@ contract FtsoV2ChangeQuoteFeed { ftsoV2 = IFastUpdater(0x9B931f5d3e24fc8C9064DB35bDc8FB4bE0E862f9); } + /** + * @dev Internal function to scale the base feed value to match the decimals of the quote feed. + */ function _scaleBaseFeedValue( uint256 _baseFeedValue, uint8 _baseFeedDecimals, uint8 _quoteDecimals ) internal pure returns (uint256) { - uint _scaledBasedFeedValue; if (_baseFeedDecimals < _quoteDecimals) { - // If base feed decimals are less than quote feed decimals, scale up - _scaledBasedFeedValue = - _baseFeedValue * - 10 ** uint256(_quoteDecimals - _baseFeedDecimals); + // Scale up if base feed decimals are less than quote feed decimals + return _baseFeedValue * 10 ** uint256(_quoteDecimals - _baseFeedDecimals); } else if (_baseFeedDecimals > _quoteDecimals) { - // If base feed decimals are more than quote feed decimals, scale down - _scaledBasedFeedValue = - _baseFeedValue / - 10 ** uint256(_baseFeedDecimals - _quoteDecimals); + // Scale down if base feed decimals are more than quote feed decimals + return _baseFeedValue / 10 ** uint256(_baseFeedDecimals - _quoteDecimals); } else { - // If base feed decimals are equal to quote feed decimals, return as is - _scaledBasedFeedValue = _baseFeedValue; + // No scaling needed if decimals are equal + return _baseFeedValue; } - return _scaledBasedFeedValue; } - function getNewQuoteFeedValue( - uint256[] calldata _baseAndQuoteFeedIndexes - ) public view returns (uint256) { + /** + * @dev Function to compute the new quote feed value based on the base and quote feed values. + * @param _baseAndQuoteFeedIndexes Array containing the indexes of the base and quote feeds. + * @return The computed new quote feed value. + */ + function getNewQuoteFeedValue(uint256[] calldata _baseAndQuoteFeedIndexes) + external + view + returns (uint256) + { require( _baseAndQuoteFeedIndexes.length == 2, - "invalid _baseAndQuoteFeedIndexes, should be of length 2" + "Invalid feed indexes. Please provide exactly two indexes." ); - // Fetch the current feed values and decimals of the base and quote feeds - ( - uint256[] memory feedValues, - int8[] memory decimals, - /* uint64 timestamp */ - ) = ftsoV2.fetchCurrentFeeds(_baseAndQuoteFeedIndexes); - // Set the new quote decimals to the quote feed decimals - uint8 _newQuoteDecimals = uint8(decimals[1]); - // Scale the base feed value to the new quote decimals + (uint256[] memory feedValues, int8[] memory decimals, ) = ftsoV2.fetchCurrentFeeds(_baseAndQuoteFeedIndexes); + + uint8 newQuoteDecimals = uint8(decimals[1]); uint256 scaledBaseFeedValue = _scaleBaseFeedValue( feedValues[0], uint8(decimals[0]), - _newQuoteDecimals + newQuoteDecimals ); - // Calculate the new quote feed value - uint256 newQuoteFeedValue = (scaledBaseFeedValue * - 10 ** uint256(_newQuoteDecimals)) / feedValues[1]; + + // Prevent division by zero + require(feedValues[1] != 0, "Division by zero"); + + uint256 newQuoteFeedValue = (scaledBaseFeedValue * 10**uint256(newQuoteDecimals)) / feedValues[1]; return newQuoteFeedValue; } } diff --git a/code_examples/developer-hub-solidity/FtsoV2FeedConsumer.sol b/code_examples/developer-hub-solidity/FtsoV2FeedConsumer.sol index 8e7e6e35..9402484b 100644 --- a/code_examples/developer-hub-solidity/FtsoV2FeedConsumer.sol +++ b/code_examples/developer-hub-solidity/FtsoV2FeedConsumer.sol @@ -7,7 +7,7 @@ interface IFastUpdater { ) external view - returns (uint256[] memory _feedValues, int8[] memory _decimals); + returns (uint256[] memory _feedValues, int8[] memory _decimals, int64 _timestamp); } /** @@ -32,9 +32,9 @@ contract FtsoV2FeedConsumer { * Get the current value of the feeds. */ function getFtsoV2CurrentFeedValues() - public + external view - returns (uint256[] memory _feedValues, int8[] memory _decimals) + returns (uint256[] memory _feedValues, int8[] memory _decimals, int64 _timestamp) { return ftsoV2.fetchCurrentFeeds(feedIndexes); } diff --git a/docs/2-network.mdx b/docs/2-network.mdx index cdfee1f3..9354b0ef 100644 --- a/docs/2-network.mdx +++ b/docs/2-network.mdx @@ -9,7 +9,7 @@ import TabItem from "@theme/TabItem"; import IconExternalLink from "@theme/Icon/ExternalLink"; import IconCopy from "@theme/Icon/Copy"; -Flare has four networks, and choosing the right one based on your work is important. All of the networks are permissionless: +Flare has four networks, each serving different purposes, so choosing the right one is crucial. All of these networks operate on a permissionless basis: - **Flare Mainnet.** The production network where all the action happens. Transactions cost real money here. @@ -17,13 +17,13 @@ Flare has four networks, and choosing the right one based on your work is import - **Songbird Canary-Network.** Experimental proving ground for Flare, test your applications in a real-world environment. -- **Songbird Testnet Coston.** Songbird's testnet. +- **Songbird Testnet Coston.** This is the testnet for the Songbird network. The most common development tracks are: -- **Flare Testnet Coston2 → Flare Mainnet** (Recommended for application developers) +- **Flare Testnet Coston2 → Flare Mainnet**: Recommended track for application developers -- **Songbird Testnet Coston → Songbird Canary-Network → Flare Mainnet** (Required for all protocol level changes) +- **Songbird Testnet Coston → Songbird Canary-Network → Flare Mainnet**: Required track for all protocol level changes ## Configuration @@ -91,7 +91,7 @@ Configuration for all Flare networks, along with public and private RPCs, blockc ## Supported Wallets -Several browser and mobile app based wallets such as MetaMask, Rabby and Bifrost support Flare. Find some options that might be right for you on the [Flare Wallets](https://flare.network/wallets/) page. +Several browser and mobile app based wallets such as MetaMask, Rabby and Bifrost support Flare. Discover suitable options for your needs on the [Flare Wallets](https://flare.network/wallets/) page. ## Transaction format diff --git a/docs/ftso/0-overview.mdx b/docs/ftso/0-overview.mdx index a8810aeb..869234c2 100644 --- a/docs/ftso/0-overview.mdx +++ b/docs/ftso/0-overview.mdx @@ -13,10 +13,10 @@ The **F**lare **T**ime **S**eries **O**racle (FTSO) is an [enshrined oracle](../ - **Secure.** FTSOv2 is enshrined into the core protocol of Flare, and every single oracle feed inherits the economic security of the entire network. -- **Fast.** FTSOv2 provides block-latency feeds, which incrementally update every ≈1.8 seconds on Flare. This is over 90x faster than FTSOv1. +- **Fast.** FTSOv2 introduces block-latency feeds, incrementally updating every ≈1.8 seconds on Flare. This is over 90x faster than FTSOv1. - **Scalable.** FTSOv2 leverages FlareDA, a data availability layer, to support up to 1000 feeds with historical data. Feeds include different asset classes such as equities, commodities, and cryptocurrencies. - **Decentralized.** FTSOv2 has around 100 independent data providers for every feed. The providers are chosen by Flare users, whose delegated stake imposes an economic cost to misbehavior. -- **Free.** FTSOv2's block-latency feeds have no costs (not even gas!) to query on Flare. Feeds from FlareDA are also free to access and verify locally, and only have minimal gas costs to verify on-chain. +- **Cost-effective.** FTSOv2's block-latency feeds have no costs (not even gas!) to query on Flare. Feeds from FlareDA are also free to access and verify locally, and only have minimal gas costs to verify on-chain. diff --git a/docs/ftso/1-getting-started.mdx b/docs/ftso/1-getting-started.mdx index 431a380b..059747df 100644 --- a/docs/ftso/1-getting-started.mdx +++ b/docs/ftso/1-getting-started.mdx @@ -11,16 +11,12 @@ import DeployContract from "/static/img/ftso-getting-started/3-deploy-contract.p import ConfirmDeployInMetamask from "/static/img/ftso-getting-started/4-confirm-deploy-in-metamask.png"; import QueryLatestFeeds from "/static/img/ftso-getting-started/5-query-latest-feeds.png"; -You can use FTSOv2 to connect your smart contracts to real-world data feeds. FTSOv2 leverages Flare's network of 100 independent data providers to source off-chain data and deliver it on-chain. This section focuses on consuming FTSOv2's block-latency feeds on Flare with an on-chain Solidity contract. +You can utilize FTSOv2 to connect your smart contracts with real-world data feeds. FTSOv2 harnesses Flare's network of 100 independent data providers to fetch off-chain data and deliver it on-chain. This section demonstrates how to consume FTSOv2's block-latency feeds on Flare using an on-chain Solidity contract. -:::note +:::info If you are new to smart contract development, learn how to [deploy your first smart contract](../../guides/deploy-first-contract) before you start this guide. ::: -:::note -To read FTSOv2 feeds off-chain or use different languages, see the language specific guides for [Python](../../guides/flare-for-python-developers), [Rust](../../guides/flare-for-rust-developers), [JavaScript](../../guides/flare-for-javascript-developers), or [Go](../../guides/flare-for-go-developers) -::: - ## Sample contract This example smart contact queries the latest feed values for FLR/USD, BTC/USD and ETH/USD from FTSOv2 on Flare Testnet Coston. diff --git a/docs/ftso/2-feeds.mdx b/docs/ftso/2-feeds.mdx index 8245c1d9..77f01aa0 100644 --- a/docs/ftso/2-feeds.mdx +++ b/docs/ftso/2-feeds.mdx @@ -3,9 +3,9 @@ slug: feeds title: Block-Latency Feeds --- -FTSOv2's block-latency feeds incrementally update with each new block on Flare, approximately every 1.8 seconds. These feeds have a single entrypoint function and primarily support cryptocurrency price feeds, they are also free (not even gas!) to query and use in your decentralized application on Flare. +FTSOv2's block-latency feeds update incrementally with each new block on Flare, approximately every 1.8 seconds. These feeds have a single entrypoint function and primarily support cryptocurrency price feeds. Moreover, they come with the added advantage of being completely free to query and utilize in your decentralized application on Flare, with no gas costs involved. -The feed indexes listed below are used as inputs to the [`fetchCurrentFeeds`](solidity-reference/IFastUpdater#fetchcurrentfeeds) entrypoint function. You can query any number of feeds in a single call by passing an array of feed indexes to the function. Querying feeds outside of the supported indexes will cause the entire transaction to revert. +The feed indexes listed below serve as inputs to the [`fetchCurrentFeeds`](solidity-reference/IFastUpdater#fetchcurrentfeeds) entrypoint function. By passing an array of feed indexes to the function, you can query any number of feeds in a single call. However, attempting to query feeds outside of the supported indexes will result in the entire transaction reverting. ```solidity title="Entrypoint function signature" function fetchCurrentFeeds( diff --git a/docs/ftso/guides/change-quote-feed.mdx b/docs/ftso/guides/change-quote-feed.mdx index 29a24c00..81376f2f 100644 --- a/docs/ftso/guides/change-quote-feed.mdx +++ b/docs/ftso/guides/change-quote-feed.mdx @@ -1,6 +1,6 @@ --- title: Change quote feed -tags: [ftso, oracle] +tags: [quickstart, ftso, solidity] slug: change-quote-feed description: Convert the feeds to a new quote feed. sidebar_position: 2 @@ -14,12 +14,15 @@ This guide will show you how to fetch the latest feed values for two feeds and c // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import { IFastUpdater } from "@flarenetwork/flare-periphery-contracts/flare/ftso/userInterfaces/IFastUpdater.sol"; +interface IFastUpdater { + function fetchCurrentFeeds( + uint256[] calldata _feedIndexes + ) + external + view + returns (uint256[] memory _feedValues, int8[] memory _decimals, int64 _timestamp); +} -/** - * THIS IS AN EXAMPLE CONTRACT. - * DO NOT USE THIS CODE IN PRODUCTION. - */ contract FtsoV2ChangeQuoteFeed { IFastUpdater internal ftsoV2; @@ -32,54 +35,54 @@ contract FtsoV2ChangeQuoteFeed { ftsoV2 = IFastUpdater(0x9B931f5d3e24fc8C9064DB35bDc8FB4bE0E862f9); } + /** + * @dev Internal function to scale the base feed value to match the decimals of the quote feed. + */ function _scaleBaseFeedValue( uint256 _baseFeedValue, uint8 _baseFeedDecimals, uint8 _quoteDecimals ) internal pure returns (uint256) { - uint _scaledBasedFeedValue; if (_baseFeedDecimals < _quoteDecimals) { - // If base feed decimals are less than quote feed decimals, scale up - _scaledBasedFeedValue = - _baseFeedValue * - 10 ** uint256(_quoteDecimals - _baseFeedDecimals); + // Scale up if base feed decimals are less than quote feed decimals + return _baseFeedValue * 10 ** uint256(_quoteDecimals - _baseFeedDecimals); } else if (_baseFeedDecimals > _quoteDecimals) { - // If base feed decimals are more than quote feed decimals, scale down - _scaledBasedFeedValue = - _baseFeedValue / - 10 ** uint256(_baseFeedDecimals - _quoteDecimals); + // Scale down if base feed decimals are more than quote feed decimals + return _baseFeedValue / 10 ** uint256(_baseFeedDecimals - _quoteDecimals); } else { - // If base feed decimals are equal to quote feed decimals, return as is - _scaledBasedFeedValue = _baseFeedValue; + // No scaling needed if decimals are equal + return _baseFeedValue; } - return _scaledBasedFeedValue; } - function getNewQuoteFeedValue( - uint256[] calldata _baseAndQuoteFeedIndexes - ) public view returns (uint256) { + /** + * @dev Function to compute the new quote feed value based on the base and quote feed values. + * @param _baseAndQuoteFeedIndexes Array containing the indexes of the base and quote feeds. + * @return The computed new quote feed value. + */ + function getNewQuoteFeedValue(uint256[] calldata _baseAndQuoteFeedIndexes) + external + view + returns (uint256) + { require( _baseAndQuoteFeedIndexes.length == 2, - "invalid _baseAndQuoteFeedIndexes, should be of length 2" + "Invalid feed indexes. Please provide exactly two indexes." ); - // Fetch the current feed values and decimals of the base and quote feeds - ( - uint256[] memory feedValues, - int8[] memory decimals, - /* uint64 timestamp */ - ) = ftsoV2.fetchCurrentFeeds(_baseAndQuoteFeedIndexes); - // Set the new quote decimals to the quote feed decimals - uint8 _newQuoteDecimals = uint8(decimals[1]); - // Scale the base feed value to the new quote decimals + (uint256[] memory feedValues, int8[] memory decimals, ) = ftsoV2.fetchCurrentFeeds(_baseAndQuoteFeedIndexes); + + uint8 newQuoteDecimals = uint8(decimals[1]); uint256 scaledBaseFeedValue = _scaleBaseFeedValue( feedValues[0], uint8(decimals[0]), - _newQuoteDecimals + newQuoteDecimals ); - // Calculate the new quote feed value - uint256 newQuoteFeedValue = (scaledBaseFeedValue * - 10 ** uint256(_newQuoteDecimals)) / feedValues[1]; + + // Prevent division by zero + require(feedValues[1] != 0, "Division by zero"); + + uint256 newQuoteFeedValue = (scaledBaseFeedValue * 10**uint256(newQuoteDecimals)) / feedValues[1]; return newQuoteFeedValue; } } diff --git a/docs/ftso/guides/read-feeds-offchain.mdx b/docs/ftso/guides/read-feeds-offchain.mdx index f880b6a1..f8621709 100644 --- a/docs/ftso/guides/read-feeds-offchain.mdx +++ b/docs/ftso/guides/read-feeds-offchain.mdx @@ -1,6 +1,6 @@ --- title: Read feeds offchain -tags: [ftso, oracle] +tags: [quickstart, ftso, python, rust, javascript, go] slug: read-feeds-offchain description: Read FTSOv2 feeds using Python, Rust, JS or Go. sidebar_position: 1 diff --git a/guides/2024-06-03-deploy-first-contract.mdx b/guides/2024-06-03-deploy-first-contract.mdx index efac1b40..8fdfa1e9 100644 --- a/guides/2024-06-03-deploy-first-contract.mdx +++ b/guides/2024-06-03-deploy-first-contract.mdx @@ -87,7 +87,7 @@ Now that you configured your wallet and funded it with testnet C2FLR, you can wr Your first contract is a simple `HelloWorld.sol` example. This example shows you how to set and retrieve variables in a smart contract onchain. -```solidity +```solidity title="HelloWorld.sol" // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; @@ -170,6 +170,45 @@ Since you deployed the contract to a blockchain, multiple nodes on the test netw Now you know how to deploy and call example contracts on Flare's testnet. You can write your own contracts and test them using this same process. +
+Didn't understand the contract? + +Let's break down the `HelloWorld` contract: + +```solidity title="HelloWorld.sol" +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/** + * THIS IS AN EXAMPLE CONTRACT. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +contract HelloWorld { + string public message; + + constructor(string memory initialMessage) { + message = initialMessage; + } + + function updateMessage(string memory newMessage) public { + message = newMessage; + } +} +``` + +1. **Pragma Directive:** The `pragma solidity ^0.8.20;` statement specifies the version of the Solidity compiler the contract should use. In this case, it's indicating that the contract is compatible with Solidity versions from 0.8.20 up to, but not including, version 0.9.0. + +2. **Contract Declaration:** The `contract HelloWorld { ... }` statement defines a new Solidity contract named `HelloWorld`. + +3. **State Variable:** `string public message`; declares a state variable named message, which is of type `string` and is publicly accessible (due to the `public` visibility modifier). This variable will store a message that can be read by any external entity. + +4. **Constructor:** The `constructor(string memory initialMessage) { ... }` function is a special function that is executed only once when the contract is deployed. It initializes the `message` state variable with the value passed as `initialMessage` when the contract is deployed. + +5. **Function `updateMessage`:** This function allows anyone to update the `message` state variable. It takes a `newMessage` parameter of type `string`, updates the `message` variable with the new value, and is publicly accessible (`public` visibility modifier). + +
+ :::tip[What's next?] Read FTSOv2's [Getting Started](../docs/ftso/getting-started) guide to learn how to connect your smart contracts to Flare's enshrined oracle and retrieve onchain data feeds. diff --git a/guides/tags.yml b/guides/tags.yml index 28ad89a0..6f51b716 100644 --- a/guides/tags.yml +++ b/guides/tags.yml @@ -1,4 +1,7 @@ quickstart: +intermediate: +advanced: +ftso: python: javascript: rust: