Skip to content

feat(docs): add support for hardhat FTSO guide and fix FTSO interfaces #608

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

Merged
merged 21 commits into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
156 changes: 141 additions & 15 deletions docs/ftso/guides/build-first-app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Build your first FTSOv2 app
tags: [intermediate, ftso, solidity]
slug: build-first-app
description: Use FTSOv2 in your Foundry project.
description: Use FTSOv2 in your Foundry or Hardhat project.
keywords:
[
ftso,
Expand All @@ -17,25 +17,39 @@ sidebar_position: 1
---

import CodeBlock from "@theme/CodeBlock";
import FtsoV2FeedConsumer from "!!raw-loader!/examples/developer-hub-solidity/FtsoV2FeedConsumer_foundry.sol";
import FtsoV2FeedConsumerTest from "!!raw-loader!/examples/developer-hub-solidity/FtsoV2FeedConsumer_foundry.t.sol";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import FtsoV2FeedConsumerFoundry from "!!raw-loader!/examples/developer-hub-solidity/FtsoV2FeedConsumer_foundry.sol";
import FtsoV2FeedConsumerTestFoundry from "!!raw-loader!/examples/developer-hub-solidity/FtsoV2FeedConsumer_foundry.t.sol";
import FtsoV2ConsumerHardhat from "!!raw-loader!/examples/developer-hub-solidity/FTSOV2Consumer_hardhat.sol";
import FtsoV2ConsumerTestHardhat from "!!raw-loader!/examples/developer-hub-javascript/ftso_v2_consumer_hardhat.ts";
import FtsoV2ConsumerHardhatDeploy from "!!raw-loader!/examples/developer-hub-javascript/deployFTSOConsumer.ts";

This guide is for developers who want to build an FTSOv2 application using Foundry. In this guide, you will learn how to:
This guide is for developers who want to build a FTSOv2 application.

Choose your development framework:

<Tabs groupId="framework">
<TabItem value="foundry" label="Foundry" default>

## Building with Foundry

In this guide, you will learn how to:

- Create a contract to read the price of FLR/USD from FTSOv2 using [flare-periphery-contracts](https://www.npmjs.com/package/@flarenetwork/flare-periphery-contracts).

- Compile your contract using Foundry [forge](https://book.getfoundry.sh/reference/forge/).

- Deploy your contract to Flare Testnet Coston2, and interact with it using Foundry [cast](https://book.getfoundry.sh/reference/cast/).

## Prerequisites
### Prerequisites

Ensure you have the following tools installed:

- [Foundry](https://book.getfoundry.sh/getting-started/installation)
- [Node.js](https://nodejs.org/en/download/)

## Clone the Foundry template
### Clone the Foundry template

1. Clone the [flare-foundry-starter](https://github.com/flare-foundation/flare-foundry-starter) and navigate into the project directory:

Expand All @@ -61,14 +75,14 @@ Ensure you have the following tools installed:
surl/=dependencies/surl-0.0.0/
```

## Create and compile a contract
### Create and compile a contract

Now, you can create a contract that consumes data from FTSOv2.

1. Create a contract file `src/FtsoV2FeedConsumer.sol`, and add the following code to it:

<CodeBlock language="solidity" title="src/FtsoV2FeedConsumer.sol">
{FtsoV2FeedConsumer}
{FtsoV2FeedConsumerFoundry}
</CodeBlock>

2. Set EVM version to `london` in `foundry.toml`:
Expand All @@ -94,14 +108,14 @@ Now, you can create a contract that consumes data from FTSOv2.
Compiler run successful!
```

## Write tests
### Write tests

Before deploying, it's important to write tests for your contract.

1. Create a test file `test/FtsoV2FeedConsumer.t.sol`, and add the following code:
1. Create a test file `test/FtsoV2FeedConsumer_foundry.t.sol`, and add the following code:

<CodeBlock language="solidity" title="test/FtsoV2FeedConsumer.t.sol">
{FtsoV2FeedConsumerTest}
<CodeBlock language="solidity" title="test/FtsoV2FeedConsumer_foundry.t.sol">
{FtsoV2FeedConsumerTestFoundry}
</CodeBlock>

2. Run the tests:
Expand All @@ -118,7 +132,7 @@ Before deploying, it's important to write tests for your contract.
[⠃] Solc 0.8.27 finished in 797.51ms
Compiler run successful!

Ran 2 tests for test/FtsoV2FeedConsumer.t.sol:FtsoV2FeedConsumerTest
Ran 2 tests for test/FtsoV2FeedConsumer_foundry.t.sol:FtsoV2FeedConsumerTestFoundry
[PASS] testCheckFees() (gas: 21085)
[PASS] testGetFlrUsdPrice() (gas: 25610)
Logs:
Expand All @@ -132,7 +146,7 @@ Before deploying, it's important to write tests for your contract.
Ran 1 test suite in 122.65ms (7.72ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)
```

## Deploy and interact with the contract
### Deploy and interact with the contract

You can now deploy your contract to Flare Testnet Coston2.

Expand Down Expand Up @@ -309,7 +323,7 @@ You can now deploy your contract to Flare Testnet Coston2.
"removed": false
}
],
"logsBloom": "0x00020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"logsBloom": "0x000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000004000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"type": "0x2",
"transactionHash": "0x3fdc9cf00456a7878476877b6f8ae5c994dd3c224ca792f965f718340fd98402",
"transactionIndex": "0x0",
Expand All @@ -329,6 +343,118 @@ You can see the transaction using the [Coston2 Explorer](https://coston2.testnet

Congratulations! You've built your first app using FTSOv2.

</TabItem>

<TabItem value="hardhat" label="Hardhat">

## Building with Hardhat

In this guide, you will learn how to:

- Create a contract to read the price of FLR/USD from FTSOv2 using [flare-periphery-contracts](https://www.npmjs.com/package/@flarenetwork/flare-periphery-contracts).

- Compile your contract using [Hardhat](https://hardhat.org) and run tests.

- Deploy your contract to Flare Testnet Coston2.

### Prerequisites

Ensure you have the following tools installed:

- [Node.js](https://nodejs.org/en) v18.0 or higher
- [npm](https://nodejs.org/en/learn/getting-started/an-introduction-to-the-npm-package-manager) or [yarn](https://yarnpkg.com)

### Clone the Hardhat template

1. Clone the [flare-hardhat-starter](https://github.com/flare-foundation/flare-hardhat-starter) and install dependencies:

```bash
git clone https://github.com/flare-foundation/flare-hardhat-starter.git
cd flare-hardhat-starter
yarn install
```

2. Copy the environment file and set your private key:

```bash
cp .env.example .env
```

:::danger

- Never share your private keys.
- Never put your private keys in source code.
- Never commit private keys to a Git repository.
:::

### Create and compile a contract

1. Create a contract file `contracts/FTSOV2Consumer.sol`:

<CodeBlock language="solidity" title="contracts/FTSOV2Consumer.sol">
{FtsoV2ConsumerHardhat}
</CodeBlock>

2. Set EVM version to `london` in `hardhat.config.ts`:

```typescript
module.exports = {
solidity: {
version: "0.8.27",
settings: {
evmVersion: "london",
optimizer: {
enabled: true,
runs: 200,
},
},
},
};
```

3. Compile the contract:

```bash
npx hardhat compile
```

### Write tests

1. Create a test directory and file `test/FtsoV2Consumer.test.ts`:

<CodeBlock language="typescript" title="test/FtsoV2ConsumerHardhat.ts">
{FtsoV2ConsumerTestHardhat}
</CodeBlock>

2. Run the tests:

```bash
npx hardhat test
```

### Deploy and interact with the contract

1. Create a deployment script `scripts/deployFTSOConsumer.ts`:

<CodeBlock language="typescript" title="scripts/deployFTSOConsumer.ts">
{FtsoV2ConsumerHardhatDeploy}
</CodeBlock>

2. Deploy to Coston2:

```bash
npx hardhat run scripts/deployFTSOConsumer.ts --network coston2
```

3. Interact with the contract:

Copy and paste the deployed contract address into the Coston2 block explorer [here](https://coston2-explorer.flare.network/) to view and interact with the contract.

Congratulations! You've built your first FTSOv2 app using Hardhat.

</TabItem>
</Tabs>

:::tip[What's next]

Learn how to [read feeds offchain](read-feeds-offchain) using JavaScript, Python, Rust and Go, or learn how to [change quote feed](change-quote-feed) with an onchain Solidity contract.
Expand Down
102 changes: 102 additions & 0 deletions examples/developer-hub-javascript/deployFTSOConsumer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { ethers, run } from "hardhat";
import { FtsoV2ConsumerContract } from "../typechain-types";

const FtsoV2Consumer = artifacts.require("FtsoV2Consumer");

async function verifyContract(address: string) {
console.log("\nVerifying contract...");
try {
await run("verify:verify", { address });
console.log("Contract verified successfully");
} catch (error) {
console.error("Error verifying contract:", error);
}
}

async function callGetFlrUsdPrice(ftsoV2Consumer: FtsoV2ConsumerContract) {
console.log("\nCalling getFlrUsdPrice...");
try {
const result = await ftsoV2Consumer.getFlrUsdPrice();
console.log("FLR/USD Price Data:");
console.log(" Price:", result[0].toString());
console.log(" Decimals:", result[1].toString());
console.log(
" Timestamp:",
new Date(result[2].toNumber() * 1000).toISOString(),
);
} catch (error) {
console.error("Error calling getFlrUsdPrice:", error);
}
}

async function callGetFlrUsdPriceWei(ftsoV2Consumer: FtsoV2ConsumerContract) {
console.log("\nCalling getFlrUsdPriceWei...");
try {
const resultWei = await ftsoV2Consumer.getFlrUsdPriceWei();
console.log("FLR/USD Price Data (Wei):");
console.log(" Price (Wei):", resultWei[0].toString());
console.log(
" Timestamp:",
new Date(resultWei[1].toNumber() * 1000).toISOString(),
);
} catch (error) {
console.error("Error calling getFlrUsdPriceWei:", error);
}
}

async function callFtsoV2CurrentFeedValues(
ftsoV2Consumer: FtsoV2ConsumerContract,
) {
console.log("\nCalling getFtsoV2CurrentFeedValues...");
try {
const feedValuesResult = await ftsoV2Consumer.getFtsoV2CurrentFeedValues();
console.log("Current Feed Values (FLR/USD, BTC/USD, ETH/USD):");
const feedIds = ["FLR/USD", "BTC/USD", "ETH/USD"]; // Match order in contract
for (let i = 0; i < feedValuesResult[0].length; i++) {
console.log(` Feed ${feedIds[i]}:`);
console.log(` Price: ${feedValuesResult[0][i].toString()}`);
console.log(` Decimals: ${feedValuesResult[1][i].toString()}`);
}
console.log(
` Timestamp: ${new Date(feedValuesResult[2].toNumber() * 1000).toISOString()}`,
);
} catch (error) {
console.error("Error calling getFtsoV2CurrentFeedValues:", error);
}
}

async function callContractFunctions(ftsoV2Consumer: FtsoV2ConsumerContract) {
await callGetFlrUsdPrice(ftsoV2Consumer);
await callGetFlrUsdPriceWei(ftsoV2Consumer);
await callFtsoV2CurrentFeedValues(ftsoV2Consumer);
}

// --- Main Deployment Script ---

async function main() {
const [deployer] = await ethers.getSigners();

console.log("Deploying contracts with the account:", deployer.address);

// Deploy FtsoV2Consumer
const ftsoV2Consumer: FtsoV2ConsumerContract = await FtsoV2Consumer.new(
"0x01464c522f55534400000000000000000000000000", // Deploying contract with FLR Feed (see more feeds here: https://dev.flare.network/ftso/feeds)
);
await ftsoV2Consumer.deployed();
console.log("FtsoV2Consumer deployed to:", ftsoV2Consumer.address);

// Verify the contract
await verifyContract(ftsoV2Consumer.address);

// Call the contract functions
await callContractFunctions(ftsoV2Consumer);

console.log("\nDeployment and calling script finished.");
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error("Unhandled error in main execution:", error);
process.exit(1);
});
Loading
Loading