Skip to content

add fuel example #386

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 2 commits into from
Jul 31, 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
1 change: 1 addition & 0 deletions pages/price-feeds/use-real-time-data/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"evm": "in EVM Contracts",
"solana": "in Solana and SVM Programs",
"starknet": "in Starknet Contracts",
"fuel": "in Fuel Contracts",
"aptos": "in Aptos Contracts",
"sui": "in Sui Contracts",
"cosmwasm": "in CosmWasm Contracts",
Expand Down
187 changes: 187 additions & 0 deletions pages/price-feeds/use-real-time-data/fuel.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
---
description: Consume Pyth Network prices in Fuel applications
---

import { Callout, Tabs } from "nextra/components";

# How to Use Real-Time Data in Fuel Contracts

This guide explains how to use real-time Pyth data in Fuel contracts.

## Install the Pyth SDK

Use the following dependency in your `Forc.toml` file to use the latest Pyth Fuel package:

```toml copy
[dependencies]
pyth_interface = { git = "https://github.com/pyth-network/pyth-crosschain", tag = "pyth-fuel-contract-v0.5.0" }
```

Pyth also provides a javascript SDK to interact with the Pyth contract on Fuel. You can install it using the following command:

<Tabs items={["npm", "yarn"]}>
<Tabs.Tab>```npm install --save @pythnetwork/pyth-fuel-js ```</Tabs.Tab>
<Tabs.Tab>```yarn add @pythnetwork/pyth-fuel-js ```</Tabs.Tab>
</Tabs>

## Write Contract Code

The code snippet below provides an example module fetching the ETH/USD price from Pyth price feeds:

```sway copy
contract;

use pyth_interface::{data_structures::price::{Price, PriceFeedId}, PythCore};

use std::bytes::Bytes;

abi UpdatePrice {
fn valid_time_period() -> u64;
fn get_price(price_feed_id: PriceFeedId) -> Price;
fn get_price_unsafe(price_feed_id: PriceFeedId) -> Price;
fn update_fee(update_data: Vec<Bytes>) -> u64;
#[payable]
fn update_price_feeds(update_fee: u64, update_data: Vec<Bytes>);
}

const PYTH_CONTRACT_ID = 0x1ab91bc1402a187055d3e827017ace566a103ce2a4126517da5d656d6a436aea; // Testnet Contract
const FUEL_ETH_BASE_ASSET_ID = 0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07;

impl UpdatePrice for Contract {
fn valid_time_period() -> u64 {
let pyth_contract = abi(PythCore, PYTH_CONTRACT_ID);
let period = pyth_contract.valid_time_period();
period
}
fn get_price(price_feed_id: PriceFeedId) -> Price {
let pyth_contract = abi(PythCore, PYTH_CONTRACT_ID);
let price = pyth_contract.price(price_feed_id);
price
}
fn get_price_unsafe(price_feed_id: PriceFeedId) -> Price {
let pyth_contract = abi(PythCore, PYTH_CONTRACT_ID);
let price = pyth_contract.price_unsafe(price_feed_id);
price
}
fn update_fee(update_data: Vec<Bytes>) -> u64 {
let pyth_contract = abi(PythCore, PYTH_CONTRACT_ID);
let fee = pyth_contract.update_fee(update_data);
fee
}
#[payable]
fn update_price_feeds(update_fee: u64, update_data: Vec<Bytes>) {
let pyth_contract = abi(PythCore, PYTH_CONTRACT_ID);
pyth_contract
.update_price_feeds {
asset_id: FUEL_ETH_BASE_ASSET_ID,
coins: update_fee,
}(update_data);
}
}
```

The `update_data` argument contains verified prices from Pyth.
Calling `pyth_contract.update_price_feeds` with this value updates the on-chain Pyth price and ensures your application has recent price data.
The `update_data` can be fetched from Hermes; Consult [Fetch Price Updates](https://docs.pyth.network/price-feeds/fetch-price-updates) for more information on how to fetch the `update_data`.

<Callout type="info" emoji="ℹ️">
Regarding the Pyth contract on Fuel, the caller must pay the fee in the base
asset for functions like `update_price_feeds`. The fee is currently set to the
minimum possible value (1 wei).
</Callout>

The code snippet above does the following things:

1. Defines an `UpdatePrice` ABI with functions to interact with the Pyth contract.
2. Implements the `UpdatePrice` ABI for the contract, providing the following functionality:

- `valid_time_period()`: Retrieves the valid time period from the Pyth contract.
- `get_price(price_feed_id)`: Gets the price for a given price feed ID.
- `get_price_unsafe(price_feed_id)`: Gets the price for a given price feed ID without staleness checks.
- `update_fee(update_data)`: Calculates the fee required to update the price feeds.
- `update_price_feeds(update_fee, update_data)`: Updates the price feeds with the provided data and fee.

3. Uses the `PYTH_CONTRACT_ID` constant to interact with the Pyth contract on testnet.
4. Uses the `FUEL_ETH_BASE_ASSET_ID` constant as the asset ID for paying update fees.

To use this contract, you would typically:

1. Call `update_fee()` to get the required fee for updating price feeds.
2. Call `update_price_feeds()` with the fee and update data to refresh the price feeds.
3. Use `get_price()` or `get_price_unsafe()` to read the updated prices.

### Write Client Code

The code snippet below provides an example of how to fetch price updates using NextJS, a full example can be found [here](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/fuel/fetch-and-update-btc-price).

```ts copy
import { TestContractAbi__factory } from "@/sway-api";
import PYTH_CONTRACT_ABI from "../abi/pyth-contract-abi.json";
import { arrayify, Contract, hexlify } from "fuels";
import { HermesClient } from "@pythnetwork/hermes-client";

const HERMES_ENDPOINT = "https://hermes.pyth.network/";
const FUEL_ETH_BASE_ASSET_ID =
"0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07";
const ETH_USD_PRICE_FEED_ID =
"0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"; // ETH/USD

const contractId =
CURRENT_ENVIRONMENT === "local"
? contractIds.testContract
: (process.env.NEXT_PUBLIC_TESTNET_CONTRACT_ID as string); // Testnet Contract ID
const pythContractId = process.env
.NEXT_PUBLIC_PYTH_TESTNET_CONTRACT_ID as string; // Testnet Contract ID

async function updateAndGetPrice() {
const fetchPriceUpdateData = async () => {
const connection = new HermesClient(HERMES_ENDPOINT);

// Latest price updates
const priceUpdates = await connection.getLatestPriceUpdates([
ETH_USD_PRICE_FEED_ID,
]);

const buffer = Buffer.from(priceUpdates.binary.data[0], "hex");
return buffer;
};

const updateData = await fetchPriceUpdateData();

const { waitForResult: waitForResultFee } = await contract.functions
.update_fee([arrayify(updateData)])
.addContracts([pythContract])
.call();
const { value: fee } = await waitForResultFee();

await contract.functions
.update_price_feeds(fee, [arrayify(updateData)])
.addContracts([pythContract])
.callParams({
forward: [fee, hexlify(FUEL_ETH_BASE_ASSET_ID)],
})
.call();

const { value: price } = await contract.functions
.get_price(hexlify(PRICE_FEED_ID))
.addContracts([pythContract])
.get();

console.log("Latest ETH/USD price after update:", price);
return price;
}

updateAndGetPrice().catch(console.error);
```

## Additional Resources

You may find these additional resources helpful for developing your Fuel application.

### Interface

The [Fuel Interface](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/fuel/contracts/pyth-interface/src) directory contains multiple files that define the functions and structures for interacting with the Pyth contract deployed on Fuel.

### Example Applications

- [fetch-and-update-btc-price](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/fuel/fetch-and-update-btc-price), which fetches the latest price update from Hermes and updates the Pyth price feeds on Fuel.
Loading