Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helper guides for off-chain interactions #4

Merged
merged 1 commit into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/2-network.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Flare has four networks, each serving different purposes, so choosing the right

- **Songbird Canary-Network.** Experimental proving ground for Flare, test your applications in a real-world environment.

- **Songbird Testnet Coston.** The testnet for Songbird network.
- **Songbird Testnet Coston.** The testnet for Songbird Canary-Network.

The most common development tracks are:

Expand Down
2 changes: 1 addition & 1 deletion docs/ftso/0-overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The **F**lare **T**ime **S**eries **O**racle (FTSO) is an [enshrined oracle](../

- **Fast.** FTSOv2 introduces block-latency feeds, incrementally updating every ≈1.8 seconds on Flare. This is over 90x faster than FTSOv1.

- **Scalable.** With Scaling, FTSOv2 supports up to 1000 feeds with historical data. Feeds include different asset classes such as equities, commodities, and cryptocurrencies.
- **Scalable.** FTSOv2 with Scaling supports 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.

Expand Down
87 changes: 85 additions & 2 deletions docs/ftso/guides/change-quote-feed.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,11 @@ contract FtsoV2ChangeQuoteFeed {
"Invalid feed indexes. Please provide exactly two indexes."
);
// Fetch current feeds
(uint256[] memory feedValues, int8[] memory decimals, ) = ftsoV2
.fetchCurrentFeeds(_baseAndQuoteFeedIndexes);
(
uint256[] memory feedValues,
int8[] memory decimals,
/* uint64 timestamp */
) = ftsoV2.fetchCurrentFeeds(_baseAndQuoteFeedIndexes);
uint8 newQuoteDecimals = uint8(decimals[1]);
// Scale the base feed value to match the quote feed decimals
uint256 scaledBaseFeedValue = _scaleBaseFeedValue(
Expand All @@ -92,3 +95,83 @@ contract FtsoV2ChangeQuoteFeed {
<Remix href="https://remix.ethereum.org/#version=soljson-v0.8.25+commit.b61c2a91.js&optimize=true&runs=200&gist=d6181b71e7932701efbc6c3c78898f5a">Open in Remix</Remix>

For the example of BTC and ETH, the function signature would be `getNewQuoteFeedValue([2, 9])`. This will return the value of BTC/ETH with the decimals of ETH.

<details>
<summary>Didn't understand the Solidity code?</summary>

Let's go through the Solidity contract `FtsoV2ChangeQuoteFeed` step-by-step to understand its functionality.

**Imports**

```solidity
import { IFastUpdater } from "@flarenetwork/flare-periphery-contracts/flare/ftso/userInterfaces/IFastUpdater.sol";
```

- Imports the `IFastUpdater` interface from the specified path. This interface is expected to define functions that the `FtsoV2ChangeQuoteFeed` contract will interact with.

**Internal variable**

```solidity
IFastUpdater internal ftsoV2;
```

- Declares an internal variable `ftsoV2` of type `IFastUpdater`, which will hold the address of the `FtsoV2` contract.

**Constructor**

```solidity
constructor() {
ftsoV2 = IFastUpdater(0x9B931f5d3e24fc8C9064DB35bDc8FB4bE0E862f9);
}
```

- The constructor initializes the `ftsoV2` variable with the address of the `FtsoV2` contract on the Songbird Testnet Coston network.

**Internal function**

```solidity
function _scaleBaseFeedValue(
uint256 _baseFeedValue,
uint8 _baseFeedDecimals,
uint8 _quoteDecimals
) internal pure returns (uint256) {
if (_baseFeedDecimals < _quoteDecimals) {
return _baseFeedValue * 10 ** uint256(_quoteDecimals - _baseFeedDecimals);
} else if (_baseFeedDecimals > _quoteDecimals) {
return _baseFeedValue / 10 ** uint256(_baseFeedDecimals - _quoteDecimals);
} else {
return _baseFeedValue;
}
}
```

- This internal function scales the base feed value to match the decimals of the quote feed. It adjusts the base feed value by either scaling it up or down depending on the difference in decimal places between the base and quote feeds.

**External function**

```solidity
function getNewQuoteFeedValue(
uint256[] calldata _baseAndQuoteFeedIndexes
) external view returns (uint256) {
require(
_baseAndQuoteFeedIndexes.length == 2,
"Invalid feed indexes. Please provide exactly two indexes."
);
(uint256[] memory feedValues, int8[] memory decimals, ) = ftsoV2.fetchCurrentFeeds(_baseAndQuoteFeedIndexes);
uint8 newQuoteDecimals = uint8(decimals[1]);
uint256 scaledBaseFeedValue = _scaleBaseFeedValue(feedValues[0], uint8(decimals[0]), newQuoteDecimals);
require(feedValues[1] != 0, "Division by zero");
uint256 newQuoteFeedValue = (scaledBaseFeedValue * 10 ** uint256(newQuoteDecimals)) / feedValues[1];
return newQuoteFeedValue;
}
```

- Parameters: Takes an array of two feed indexes, one for the base feed and one for the quote feed.
- Require Statement: Ensures that exactly two feed indexes are provided.
- Fetching Feeds: Uses the `fetchCurrentFeeds` function of the `ftsoV2` contract to get the current feed values and their decimals.
- Scaling Base Feed Value: Scales the base feed value to match the decimals of the quote feed using the `_scaleBaseFeedValue` function.
- Division by Zero Check: Ensures the quote feed value is not zero to prevent division by zero.
- Computing New Quote Feed Value: Calculates the new quote feed value by adjusting for the decimal difference and dividing by the quote feed value.
- Return Value: Returns the computed new quote feed value.

</details>
147 changes: 147 additions & 0 deletions docs/ftso/guides/read-feeds-offchain.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,76 @@ if __name__ == "__main__":
asyncio.run(main())
```

<details>
<summary>Didn't understand the Python code?</summary>

Let's go through the Python code step-by-step to understand its functionality.

**Imports**

```python
import asyncio
from web3 import AsyncHTTPProvider, AsyncWeb3
```

- `asyncio`: A library to write concurrent code using the `async`/`await` syntax.
- `AsyncHTTPProvider`, `AsyncWeb3`: Asynchronous versions of `web3` components for interacting with the Ethereum blockchain.

**Configuration**

```python
ADDRESS = "0x9B931f5d3e24fc8C9064DB35bDc8FB4bE0E862f9"
RPC_URL = "https://rpc.ankr.com/flare_coston"
FEED_INDEXES = [0, 2, 9]
ABI = '[...]'
```

- `ADDRESS`: The address of the `FastUpdater` smart contract on the Songbird Testnet Coston.
- `RPC_URL`: The URL of the RPC node to connect to the Ethereum network.
- `FEED_INDEXES`: List of indexes representing specific price feeds: 0 for FLR/USD, 2 for BTC/USD, and 9 for ETH/USD.
- `ABI`: The Application Binary Interface (ABI) of the FastUpdater smart contract, which describes the contract's methods and events.

**Main Asynchronous Function**

```python
async def main() -> None:
# Connect to an RPC node
w3 = AsyncWeb3(AsyncHTTPProvider(RPC_URL))
```

- Connect to the RPC node using `AsyncWeb3` and `AsyncHTTPProvider`.

```python
# Set up contract instance
ftsov2 = w3.eth.contract(address=ADDRESS, abi=ABI)
```

- Create an instance of the smart contract using its address and ABI.

```python
# Fetch current feeds
feeds, decimals, timestamp = await ftsov2.functions.fetchCurrentFeeds(
FEED_INDEXES
).call()
```

- Call the `fetchCurrentFeeds` method of the smart contract with `FEED_INDEXES` to get the current feed data.
- This method returns `feeds`, `decimals`, and `timestamp`:
- `feeds`: The price feed data.
- `decimals`: The decimal places for each feed value.
- `timestamp`: The timestamp when the feeds were last updated.

**Entry Point**

```python
if __name__ == "__main__":
asyncio.run(main())
```

- When the script is executed, it runs the `main` function within an asyncio event loop using `asyncio.run()`.

</details>

## JavaScript

This example shows two ways, one using [web3.js](https://github.com/web3/web3.js) and the other using [ethers.js](https://github.com/ethers-io/ethers.js/), to retrieve FTSOv2 feed data for FLR/USD, BTC/USD, and ETH/USD on Flare Testnet Coston.
Expand Down Expand Up @@ -199,6 +269,83 @@ async fn main() -> Result<()> {
}
```

<details>
<summary>Didn't understand the Rust code?</summary>

Let's go through the Rust code step-by-step to understand its functionality.

**Libraries and Crates**

```rust
use alloy::{primitives::U256, providers::ProviderBuilder, sol};
```

- This line imports necessary modules from the `alloy` crate. The `U256` primitive is used for handling 256-bit unsigned integers. `ProviderBuilder` is for building a provider to connect to an RPC node. The `sol` macro is used for Solidity contract interaction.

```rust
use eyre::Result;
```

- This line imports the `Result` type from the `eyre` crate for better error handling.

**Solidity Contract Interface**

```rust
sol!(
#[sol(rpc)]
FtsoV2,
r#"..."#
);
```

- This macro defines a Solidity contract interface named `FtsoV2`. The long JSON string inside the macro is the ABI (Application Binary Interface) of the contract. It specifies the functions, events, and errors of the contract, allowing Rust code to interact with the Solidity contract on the Ethereum blockchain.

**Asynchronous Main Function**

```rust
#[tokio::main] async fn main() -> Result<()> {
```

- This line uses the `#[tokio::main]` attribute to mark the main function as asynchronous, enabling it to perform asynchronous operations. The function returns a `Result<()>`, indicating it can return errors wrapped in the `eyre::Result` type.

**Initialization and Connection**

```rust
let address = "0x9B931f5d3e24fc8C9064DB35bDc8FB4bE0E862f9".parse()?;
let rpc_url = "https://rpc.ankr.com/flare_coston".parse()?;
let feed_indexes = vec![U256::from(0_u32), U256::from(2_u32), U256::from(9_u32)];
let provider = ProviderBuilder::new().on_http(rpc_url);
```

- The contract address and RPC URL are parsed into appropriate types.
- This sets up a vector of feed indexes, which correspond to specific data feeds (e.g., FLR/USD, BTC/USD, ETH/USD).
- A provider is created using `ProviderBuilder`, configured to connect via HTTP to the specified RPC URL.

**Contract Interaction**

```rust
let ftsov2 = FtsoV2::new(address, provider);
let FtsoV2::fetchCurrentFeedsReturn {
_feeds,
_decimals,
_timestamp
} = ftsov2.fetchCurrentFeeds(feed_indexes).call().await?;
```

- An instance of the `FtsoV2` contract is created using the contract address and the provider.
- The function `fetchCurrentFeeds` is called on the contract instance, passing in the feed indexes. This function is awaited asynchronously and returns the current feed data.
- The fetched feed data (`_feeds`), their decimals (`_decimals`), and the timestamp (`_timestamp`) are stored in the corresponding variables.

**Error handling**

```rust
Ok(())
```

- The function returns `Ok(())` to indicate successful execution.

</details>

## Go

This example uses the Go API from [Geth](https://geth.ethereum.org) to retrieve FTSOv2 feed data for FLR/USD, BTC/USD, and ETH/USD from Flare Testnet Coston.
Expand Down
6 changes: 3 additions & 3 deletions guides/2024-06-03-deploy-first-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ You will create and deploy a simple "Hello world" smart contract using the follo

<img src={PasteAddress} style={{ width: 400 }} />

9. After the faucet completes the transaction, you should see the testnet C2FLR in your MetaMask wallet.
9. After the faucet completes the transaction, which can take a few seconds, you should see the testnet C2FLR in your MetaMask wallet.

<img src={AfterFaucetConfirmation} style={{ width: 300 }} />

Expand Down Expand Up @@ -171,7 +171,7 @@ 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.

<details>
<summary>Didn't understand the contract?</summary>
<summary>Didn't understand the Solidity code?</summary>

Let's break down the `HelloWorld` contract:

Expand Down Expand Up @@ -201,7 +201,7 @@ contract HelloWorld {

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.
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.

Expand Down
Loading