diff --git a/apps/developer-hub/.prettierignore b/apps/developer-hub/.prettierignore index e69f4c0a14..2d76e1aff0 100644 --- a/apps/developer-hub/.prettierignore +++ b/apps/developer-hub/.prettierignore @@ -11,3 +11,4 @@ build/ node_modules/ package.json tsconfig*.json +content/docs/price-feeds/core/use-real-time-data/pull-integration/ton.mdx \ No newline at end of file diff --git a/apps/developer-hub/content/docs/price-feeds/core/api-instances-and-providers/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/api-instances-and-providers/index.mdx index a3078e6b31..ad6b8ee4a2 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/api-instances-and-providers/index.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/api-instances-and-providers/index.mdx @@ -7,6 +7,6 @@ slug: /price-feeds/core/api-instances-and-providers This documentation explains how to get access to API instances and providers for Pyth Price Feeds. See the following guides to learn more about how to access each service: -- [Hermes](api-instances-and-providers/hermes.mdx) -- [Pythnet RPC](api-instances-and-providers/pythnet-rpc.mdx) -- [Benchmarks/Historical Price](api-instances-and-providers/benchmarks.mdx) +- [Hermes](/price-feeds/core/api-instances-and-providers/hermes) +- [Pythnet RPC](/price-feeds/core/api-instances-and-providers/pythnet-rpc) +- [Benchmarks/Historical Price](/price-feeds/core/api-instances-and-providers/benchmarks) diff --git a/apps/developer-hub/content/docs/price-feeds/core/api-instances-and-providers/meta.json b/apps/developer-hub/content/docs/price-feeds/core/api-instances-and-providers/meta.json index 16e916415f..558895fb19 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/api-instances-and-providers/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/api-instances-and-providers/meta.json @@ -1,7 +1,3 @@ { - "pages": [ - "[Hermes](./hermes)", - "[Benchmarks / Historical Prices](./benchmarks)", - "[Pythnet RPC](./pythnet-rpc)" - ] + "pages": ["hermes", "benchmarks", "pythnet-rpc"] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/api-reference.mdx b/apps/developer-hub/content/docs/price-feeds/core/api-reference/index.mdx similarity index 100% rename from apps/developer-hub/content/docs/price-feeds/core/api-reference.mdx rename to apps/developer-hub/content/docs/price-feeds/core/api-reference/index.mdx diff --git a/apps/developer-hub/content/docs/price-feeds/core/api-reference/meta.json b/apps/developer-hub/content/docs/price-feeds/core/api-reference/meta.json index 23169d38f9..cf21f83283 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/api-reference/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/api-reference/meta.json @@ -1,6 +1,6 @@ { "pages": [ - "[EVM \u2197](https://api-reference.pyth.network/price-feeds/evm/getPriceNoOlderThan)", - "[Hermes \u2197](https://hermes.pyth.network/docs/)" + "[EVM](https://api-reference.pyth.network/price-feeds/evm/getPriceNoOlderThan)", + "[Hermes](https://hermes.pyth.network/docs/)" ] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/best-practices.mdx b/apps/developer-hub/content/docs/price-feeds/core/best-practices.mdx index 33e43ec1a4..0e4cfff472 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/best-practices.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/best-practices.mdx @@ -46,7 +46,7 @@ This ability is functionally equivalent to latency: it allows users to see the p The simplest way to guard against this attack vector is to incorporate a **staleness check** to ensure that the price used in a transaction is sufficiently recent. -The Pyth SDK provides the [`getPriceNoOlderThan()`](https://api-reference.pyth.network/price-feeds/evm/getPriceNoOlderThan) method to help users guard against this attack vector. This method returns the most recent price update that is not older than a specified threshold. +The Pyth SDK provides the [getPriceNoOlderThan()](https://api-reference.pyth.network/price-feeds/evm/getPriceNoOlderThan) method to help users guard against this attack vector. This method returns the most recent price update that is not older than a specified threshold. Highly latency-sensitive protocols may wish to reduce the threshold to a few seconds to better suit their needs. Please also see the section below on [latency mitigations](#latency) for additional ideas on how latency-sensitive protocols can minimize the impact of oracle latency. diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/aptos.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/aptos.mdx index 895279241e..bcf083e558 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/aptos.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/aptos.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on Aptos -description: Find Pyth price feed contract addresses on Aptos networks +title: on Aptos +description: List of Pyth price feed contract addresses on Aptos networks slug: /price-feeds/core/contract-addresses/aptos --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/cosmwasm.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/cosmwasm.mdx index dea9c8b242..d125b4cc71 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/cosmwasm.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/cosmwasm.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on CosmWasm Networks -description: Find Pyth price feed contract addresses across CosmWasm ecosystems +title: on CosmWasm +description: List of Pyth price feed contract addresses on CosmWasm networks slug: /price-feeds/core/contract-addresses/cosmwasm --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/evm.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/evm.mdx index d3fddf0d28..24d8825ba3 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/evm.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/evm.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on EVM Networks -description: Find Pyth price feed contract addresses on supported EVM mainnets and testnets +title: on EVM Networks +description: List of Pyth price feed contract addresses on supported EVM mainnets and testnets slug: /price-feeds/core/contract-addresses/evm --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/fuel.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/fuel.mdx index 9f7fd8ebaf..529012c599 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/fuel.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/fuel.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on Fuel -description: Find Pyth price feed contract addresses on Fuel mainnet and testnet +title: on Fuel +description: List of Pyth price feed contract addresses on Fuel mainnet and testnet slug: /price-feeds/core/contract-addresses/fuel --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/index.mdx index ae7bbdb1c9..4ed85ac495 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/index.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/index.mdx @@ -7,17 +7,17 @@ slug: /price-feeds/core/contract-addresses The following sections list the addresses of deployed Pyth Price Feed contracts across blockchains. The contracts are split by ecosystem into several different documents: -- [EVM](./contract-addresses/evm) -- [Solana/SVM](./contract-addresses/solana) -- [Aptos](./contract-addresses/aptos) -- [Sui](./contract-addresses/sui) -- [IOTA](./contract-addresses/iota) -- [Movement](./contract-addresses/movement) -- [TON](./contract-addresses/ton) -- [Fuel](./contract-addresses/fuel) -- [CosmWasm](./contract-addresses/cosmwasm) -- [NEAR](./contract-addresses/near) -- [Starknet](./contract-addresses/starknet) -- [Pythnet](./contract-addresses/pythnet) +- [EVM](/price-feeds/core/contract-addresses/evm) +- [Solana/SVM](/price-feeds/core/contract-addresses/solana) +- [Aptos](/price-feeds/core/contract-addresses/aptos) +- [Sui](/price-feeds/core/contract-addresses/sui) +- [IOTA](/price-feeds/core/contract-addresses/iota) +- [Movement](/price-feeds/core/contract-addresses/movement) +- [TON](/price-feeds/core/contract-addresses/ton) +- [Fuel](/price-feeds/core/contract-addresses/fuel) +- [CosmWasm](/price-feeds/core/contract-addresses/cosmwasm) +- [NEAR](/price-feeds/core/contract-addresses/near) +- [Starknet](/price-feeds/core/contract-addresses/starknet) +- [Pythnet](/price-feeds/core/contract-addresses/pythnet) Please see the relevant ecosystem document to find the Pyth contract address on your blockchain of choice. diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/iota.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/iota.mdx index dd675340ef..8c1d5c24fd 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/iota.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/iota.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on IOTA -description: Find Pyth price feed contract addresses on IOTA networks +title: on IOTA +description: List of Pyth price feed contract addresses on IOTA networks slug: /price-feeds/core/contract-addresses/iota --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/meta.json b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/meta.json index 01ca1a80b9..7b2c275a27 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/meta.json @@ -1,16 +1,16 @@ { "pages": [ - "[EVM](./evm)", - "[Solana / SVM](./solana)", - "[Aptos](./aptos)", - "[Sui](./sui)", - "[IOTA](./iota)", - "[Movement](./movement)", - "[TON](./ton)", - "[Fuel](./fuel)", - "[CosmWasm](./cosmwasm)", - "[NEAR](./near)", - "[Starknet](./starknet)", - "[Pythnet](./pythnet)" + "evm", + "solana", + "aptos", + "sui", + "iota", + "movement", + "ton", + "fuel", + "cosmwasm", + "near", + "starknet", + "pythnet" ] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/movement.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/movement.mdx index 2104459a2c..9cd6e24c79 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/movement.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/movement.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on Movement -description: Find Pyth price feed contract addresses on Movement networks +title: on Movement +description: List of Pyth price feed contract addresses on Movement networks slug: /price-feeds/core/contract-addresses/movement --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/near.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/near.mdx index 1186b05a45..b506ce95fe 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/near.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/near.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on NEAR -description: Find Pyth price feed contract addresses on NEAR networks +title: on NEAR +description: List of Pyth price feed contract addresses on NEAR networks slug: /price-feeds/core/contract-addresses/near --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/pythnet.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/pythnet.mdx index 9df1b659f2..346a3b2afd 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/pythnet.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/pythnet.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on Pythnet -description: Find Pyth price feed contract addresses on Pythnet +title: on Pythnet +description: List of Pyth price feed contract addresses on Pythnet slug: /price-feeds/core/contract-addresses/pythnet --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/solana.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/solana.mdx index 7ea6ecdbbd..b4cdeff813 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/solana.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/solana.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on Solana/SVM -description: Find Pyth price feed contract addresses on Solana and other SVM chains +title: on Solana/SVM +description: List of Pyth price feed contract addresses on Solana and other SVM chains slug: /price-feeds/core/contract-addresses/solana --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/starknet.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/starknet.mdx index 74eaf8576c..d31127184c 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/starknet.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/starknet.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on Starknet -description: Find Pyth price feed contract addresses on Starknet networks +title: on Starknet +description: List of Pyth price feed contract addresses on Starknet networks slug: /price-feeds/core/contract-addresses/starknet --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/sui.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/sui.mdx index f337e03a09..490dfb913d 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/sui.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/sui.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on Sui -description: Find Pyth price feed contract addresses on Sui networks +title: on Sui +description: List of Pyth price feed contract addresses on Sui networks slug: /price-feeds/core/contract-addresses/sui --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/ton.mdx b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/ton.mdx index 17a67639d6..e5729afb6a 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/ton.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/contract-addresses/ton.mdx @@ -1,6 +1,6 @@ --- -title: Price Feed Contract Addresses on TON -description: Find Pyth price feed contract addresses on TON networks +title: on TON +description: List of Pyth price feed contract addresses on TON networks slug: /price-feeds/core/contract-addresses/ton --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/create-tradingview-charts.mdx b/apps/developer-hub/content/docs/price-feeds/core/create-tradingview-charts.mdx index 2de72316b2..1fd95b97cd 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/create-tradingview-charts.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/create-tradingview-charts.mdx @@ -1,5 +1,5 @@ --- -title: How to Create TradingView Charts +title: Create TradingView Charts description: Learn how to build TradingView charts powered by Pyth price feeds slug: /price-feeds/core/create-tradingview-charts --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/derive-cross-rate.mdx b/apps/developer-hub/content/docs/price-feeds/core/derive-cross-rate.mdx index b040b4f071..e6c76eef77 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/derive-cross-rate.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/derive-cross-rate.mdx @@ -9,16 +9,14 @@ import { Tab, Tabs } from "fumadocs-ui/components/tabs"; This guide shows how to combine two price feeds to derive a cross rate. These are also known as "synthetic" price feeds. Cross rates or Synthetic Price feeds are useful for trading pairs that are not directly supported by Pyth. - - -### EVM - For example, if you want to trade the price of **`ETH/EUR{:jsx}`**, which is not directly supported by Pyth, you can combine the price of **`ETH/USD{:jsx}`** and **`EUR/USD{:jsx}`** to derive the price of **`ETH/EUR{:jsx}`**. -$$ +```math \large{\text{ETH/EUR} = \text{ETH/USD} \div \text{EUR/USD}} -$$ +``` + + ### Derive a cross rate The Pyth Solidity SDK provides [`deriveCrossRate`](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/ethereum/sdk/solidity/PythUtils.sol#L77) function to combine two price feeds. diff --git a/apps/developer-hub/content/docs/price-feeds/core/error-codes/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/error-codes/index.mdx index 1789ec9c83..c64f8623af 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/error-codes/index.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/error-codes/index.mdx @@ -4,4 +4,4 @@ description: Directory of error code references for Pyth price feeds slug: /price-feeds/core/error-codes --- -- [EVM](error-codes/evm) +- [EVM](/price-feeds/core/error-codes/evm) diff --git a/apps/developer-hub/content/docs/price-feeds/core/error-codes/meta.json b/apps/developer-hub/content/docs/price-feeds/core/error-codes/meta.json index 6509527e0b..33fb68d428 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/error-codes/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/error-codes/meta.json @@ -1,3 +1,5 @@ { - "pages": ["[EVM](./evm)"] + "title": "Error Codes", + "pages": ["evm"], + "defaultOpen": false } diff --git a/apps/developer-hub/content/docs/price-feeds/core/fetch-price-updates.mdx b/apps/developer-hub/content/docs/price-feeds/core/fetch-price-updates.mdx index 22d9a86c26..b70128c14d 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/fetch-price-updates.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/fetch-price-updates.mdx @@ -1,5 +1,5 @@ --- -title: How To Fetch Price Updates +title: Fetch Price Updates description: Learn how to retrieve Pyth price updates via REST, streaming, and SDK slug: /price-feeds/core/fetch-price-updates --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/cross-chain.mdx b/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/cross-chain.mdx index c30485440e..048ddffc5c 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/cross-chain.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/cross-chain.mdx @@ -7,7 +7,12 @@ slug: /price-feeds/core/how-pyth-works/cross-chain Pyth uses a cross-chain mechanism to transfer prices from [Pythnet](pythnet) to target chains. The diagram below shows how prices are delivered from Pythnet to target chains: -![Pyth cross-chain architecture](/images/Pull-Architecture-Hermes.png) +
+ Pyth cross-chain architecture +
Data providers publish their prices on Pythnet. The on-chain [oracle program](oracle-program) then aggregates prices for a feed to obtain the aggregate price and confidence. Next, the Pythnet validators send a Wormhole message on each diff --git a/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/ema-price-aggregation.mdx b/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/ema-price-aggregation.mdx index 6e093cfd3c..21d35d3962 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/ema-price-aggregation.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/ema-price-aggregation.mdx @@ -27,7 +27,12 @@ price_account .. CqFJLrT4rSpA46RQkVYWn8tdBDuQ7p7RXcp6Um76oaph In an EMA the most recent samples receive the most weight, and samples further back in time get exponentially less weight the farther in the past they are. For a 1 hour EMA, the samples 1 hour in the past get 50% of the weighting, samples 2 hours in the past get 25% of the weighting, 3 hours in the past get 12.5% of the weighting, etc. -![EMA price aggregation example 1](/images/EMA_Price_Aggregation_1.png) +
+ EMA price aggregation example 1 +
While conceptually not as simple as an SMA (Simple Moving Average), the EMA has a particularly simple implementation for streaming applications such as Pyth. The exponential weighting method allows the entire history of prices and weights to be represented by a single number. @@ -42,6 +47,11 @@ The current Pyth averaging method is a slot-weighted, inverse confidence-weighte - **Slot weighted** — The Pyth EMA uses the Pythnet slot number to measure the passage of time. The averaging period is 5921 slots, which corresponds to approximately 1 hour on Pythnet. - **Inverse confidence weighted** — Weighting each sample by 1/Confidence lets the EMA give more weight to samples with tight confidence and ignore samples with very wide confidence. Below is an example of an outlier aggregate price with a wide confidence interval. Notice how the average using inverse confidence weighting does not get pulled up by the outlier sample while the uniform weighted average does. -![EMA price aggregation example 2](/images/EMA_Price_Aggregation_2.png) +
+ EMA price aggregation example 2 +
For more details and explanations, be sure to read the dedicated blog post on this topic [here](https://pythnetwork.medium.com/whats-in-a-name-302a03e6c3e1). diff --git a/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/meta.json b/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/meta.json index 4125a08fe5..4739d99adf 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/meta.json @@ -1,11 +1,11 @@ { "pages": [ - "[Pythnet](./pythnet)", - "[Oracle Program](./oracle-program)", - "[Cross-chain](./cross-chain)", - "[Fees](./fees)", - "[Hermes](./hermes)", - "[Price Aggregation](./price-aggregation)", - "[EMA Price Aggregation](./ema-price-aggregation)" + "pythnet", + "oracle-program", + "cross-chain", + "fees", + "hermes", + "price-aggregation", + "ema-price-aggregation" ] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/price-aggregation.mdx b/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/price-aggregation.mdx index d2feadc591..055b362ca6 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/price-aggregation.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/how-pyth-works/price-aggregation.mdx @@ -10,11 +10,21 @@ Price aggregation combines the prices and confidences submitted by individual da The aggregation algorithm is designed to achieve 3 properties. First, it must be **robust to manipulation.** If most publishers are submitting a price of \$100 and one publisher submits a price of \$80, the aggregate price should remain near \$100 and not be overly influenced by the single outlying price. In the figure below, the aggregate price and confidence interval (represented by the blue star) is not influenced by the magenta publisher whose price is far away from the other publishers: -![Price aggregation example 1](/images/Price_Aggregation_1.png) +
+ Price aggregation example with an outlier +
Second, the **aggregate price should appropriately weight data sources with different levels of accuracy.** Pyth allows publishers to submit a confidence interval because they have varying levels of accuracy in observing the price of a product. This property can result in situations where one publisher reports a price of \$101 +/- 1, and another reports \$110 +/- 10. In these cases, aggregating the price to be closer to \$101 than \$110 is appropriate, as in the figure below. -![Price aggregation example 2](/images/Price_Aggregation_2.png) +
+ Price aggregation example showing weighting by accuracy +
Finally, the **aggregate confidence interval should reflect the variation between publishers' prices.** Under normal market conditions, it is reasonable to expect a product to trade at a similar price across exchanges. @@ -22,7 +32,12 @@ In these cases, aggregate confidence interval is preferable to reflect the confi However, in some rare situations, a product can trade at different prices on different exchanges. In these cases, the aggregate confidence interval should widen out to reflect the variation between these prices, as shown in the figure on the right. -![Price aggregation example 3](/images/Price_Aggregation_3.png) +
+ Price aggregation example illustrating confidence width +
**Algorithm** @@ -45,21 +60,41 @@ Finally, the bold red star depicts the aggregate price and the bold red line dep In the first scenario, one publisher with a tight confidence interval is an outlier. Although this publisher does influence the objective function (the red line is lower on the left side than the right), it does not have enough influence to affect either the aggregate price or confidence interval. -![Price aggregation example 4](/images/Price_Aggregation_4.png) +
+ Aggregation scenario with an outlier +
The second scenario depicts how publishers with tighter confidence intervals can exert more influence over the location of the aggregate price, as long as their prices are consistent with the confidence intervals of other publishers. -![Price aggregation example 5](/images/Price_Aggregation_5.png) +
+ Aggregation scenario with higher weights for tighter confidence +
The third scenario demonstrates the typical case where there are many publishers whose prices and confidence intervals roughly agree. In this case, the desired behavior is for the aggregate price and confidence to reflect those of the individual publishers. -![Price aggregation example 6](/images/Price_Aggregation_6.png) +
+ Aggregation scenario with consistent publishers +
Finally, the fourth scenario considers the case where the publishers publish distinct prices with non-overlapping confidence intervals. In this case, the confidence interval widens out because the dispersion between publishers creates a large gap between the aggregate price and the 25th/75th percentiles of the votes. -![Price aggregation example 7](/images/Price_Aggregation_7.png) +
+ Aggregation scenario with divergent publisher prices +
**Further Reading** diff --git a/apps/developer-hub/content/docs/price-feeds/core/meta.json b/apps/developer-hub/content/docs/price-feeds/core/meta.json index ba66ff0d76..45bf55e8cc 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/meta.json @@ -5,31 +5,31 @@ "create-your-first-pyth-app", "---How-To Guides---", "use-real-time-data", - "[Use Historic Price Data](./core/use-historic-price-data)", - "[Fetch Price Updates](./core/fetch-price-updates)", - "[Schedule Price Updates](./core/schedule-price-updates)", - "[Create TradingView Charts](./core/create-tradingview-charts)", - "[Derive Cross Rate](./core/derive-cross-rate)", - "[Migrate an App to Pyth](./core/migrate-an-app-to-pyth)", - "[Use Pyth for Morpho Markets](./core/use-pyth-for-morpho)", - "[Publish Data](./core/publish-data)", - "[Troubleshoot Errors](./core/troubleshoot)", + "use-historic-price-data", + "fetch-price-updates", + "schedule-price-updates", + "create-tradingview-charts", + "derive-cross-rate", + "migrate-an-app-to-pyth", + "use-pyth-for-morpho", + "publish-data", + "troubleshoot", "---Reference Material---", - "[API Reference](./core/api-reference)", - "[Price Feeds](./core/price-feeds)", - "[Current Fees](./core/current-fees)", - "[Push Feeds](./core/push-updates)", - "[Market Hours](./core/market-hours)", - "[Best Practices](./core/best-practices)", - "[Rate Limits](./core/rate-limits)", - "[Error Codes](./core/error-codes)", - "[API Instances and Providers](./api-instances-and-providers)", - "[Contract Addresses](./contract-addresses)", - "[Pythnet Reference](./core/pythnet-reference)", + "api-reference", + "price-feeds", + "current-fees", + "push-feeds", + "market-hours", + "best-practices", + "rate-limits", + "error-codes", + "api-instances-and-providers", + "contract-addresses", + "pythnet-reference", "[Example Applications \u2197](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds)", "---Understanding Pyth---", - "[What is a Pull Oracle?](./core/pull-updates)", - "[Why Update Prices](./core/why-update-prices)", - "[How Pyth Works](./core/how-pyth-works)" + "pull-updates", + "why-update-prices", + "how-pyth-works" ] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/chainlink.mdx b/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/chainlink.mdx new file mode 100644 index 0000000000..254c446ef1 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/chainlink.mdx @@ -0,0 +1,106 @@ +--- +title: From Chainlink +description: Switch Chainlink AggregatorV3 feeds to Pyth price feeds in EVM applications +slug: /price-feeds/core/migrate-an-app-to-pyth/chainlink +--- + +This guide explains how to migrate an EVM application that uses Chainlink price feeds to Pyth price feeds. +Pyth provides a Chainlink-compatible interface for its price feeds to make this process simple. +There are two main steps to the migration: + +1. Deploy the [`PythAggregatorV3`](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/ethereum/sdk/solidity/PythAggregatorV3.sol) contract to provide a Chainlink-compatible feed interface. +2. Schedule price updates for the feeds required by your app. + +## Install Pyth SDKs + +The `PythAggregatorV3` contract is provided in the [Pyth Price Feeds Solidity SDK](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ethereum/sdk/solidity). +Add this SDK to the dependencies of your EVM contract. + +**Truffle/Hardhat** + +If you are using Truffle or Hardhat, simply install the NPM package: + +```bash copy +npm install @pythnetwork/pyth-sdk-solidity +``` + +**Foundry** + +If you are using Foundry, you will need to create an NPM project if you don't already have one. +From the root directory of your project, run: + +```bash copy +npm init -y +npm install @pythnetwork/pyth-sdk-solidity +``` + +Then add the following line to your `remappings.txt` file: + +```text copy +@pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity +``` + +## Deploy Adapter Contract + +First, deploy the `PythAggregatorV3` contract from `@pythnetwork/pyth-sdk-solidity` as a replacement for your application's Chainlink price feeds. +`PythAggregatorV3` is an adapter contract that wraps the Pyth contract and implements Chainlink's `AggregatorV3Interface`. + +One important difference between Pyth and Chainlink is that the Pyth contract holds data for all price feeds; in contrast, Chainlink has separate instances of `AggregatorV3Interface` for each feed. +The adapter contract resolves this discrepancy by wrapping a single Pyth price feed. +Users should deploy an instance of this adapter for every required price feed, then point their existing app to the addresses of the deployed adapter contracts. + +The following `forge` deployment script demonstrates the expected deployment process: + +```solidity copy +// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.0; + +import "forge-std/Script.sol"; +import { PythAggregatorV3 } from "@pythnetwork/pyth-sdk-solidity/PythAggregatorV3.sol"; +import { ChainlinkApp } from "./ChainlinkApp.sol"; + +contract PythAggregatorV3Deployment is Script { + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + // Get the address for your ecosystem from: + // https://docs.pyth.network/price-feeds/core/contract-addresses/evm + address pythPriceFeedsContract = 0xff1a0f4744e8582DF1aE09D5611b887B6a12925C; + // Get the price feed ids from: + // https://docs.pyth.network/price-feeds/core/price-feeds + bytes32 ethFeedId = 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace; + bytes32 solFeedId = 0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d; + + // Deploy an instance of PythAggregatorV3 for every feed. + PythAggregatorV3 ethAggregator = new PythAggregatorV3( + pythPriceFeedsContract, + ethFeedId + ); + PythAggregatorV3 solAggregator = new PythAggregatorV3( + pythPriceFeedsContract, + solFeedId + ); + + // Pass the address of the PythAggregatorV3 contract to your chainlink-compatible app. + ChainlinkApp app = new ChainlinkApp( + address(ethAggregator), + address(solAggregator) + ); + + vm.stopBroadcast(); + } +} + +``` + +Please see the [Chainlink Migration Example](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/evm/chainlink_migration) for a runnable version of the example above. + +## Schedule Updates + +Chainlink-compatible applications typically expect on-chain price feeds to update on a schedule. +When migrating to Pyth, apps may need to schedule these price updates themselves. +This step is required because Pyth is a pull oracle; see [What is a pull oracle?](/price-feeds/core/pull-updates.mdx) to learn more about this topic. + +The [Push Feeds](/price-feeds/core/push-feeds.mdx) page shows a list of feeds that have scheduled on-chain updates. +If the feeds your application needs are not on this list, see [Schedule Price Updates](/price-feeds/core/schedule-price-updates) for several options to solve this problem. diff --git a/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/index.mdx index 882a0fd73a..9eadd7a08b 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/index.mdx +++ b/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/index.mdx @@ -1,5 +1,5 @@ --- -title: Migrate to Pyth from Another Oracle +title: Migrate to Pyth description: Resources to help move existing oracle integrations onto Pyth price feeds slug: /price-feeds/core/migrate-an-app-to-pyth --- diff --git a/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/meta.json b/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/meta.json index 3b72e50d0f..0aeb702107 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/migrate-an-app-to-pyth/meta.json @@ -1,3 +1,3 @@ { - "pages": ["[from Chainlink](./chainlink)"] + "pages": ["chainlink"] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/price-feeds/meta.json b/apps/developer-hub/content/docs/price-feeds/core/price-feeds/meta.json index bfef8a56ea..b23b60eac7 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/price-feeds/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/price-feeds/meta.json @@ -1,6 +1,3 @@ { - "pages": [ - "[Price Feed IDs](./price-feed-ids)", - "[Asset Classes](./asset-classes)" - ] + "pages": ["price-feed-ids", "asset-classes"] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/price-feeds/price-feed-ids.mdx b/apps/developer-hub/content/docs/price-feeds/core/price-feeds/price-feed-ids.mdx new file mode 100644 index 0000000000..c6a43637ff --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/price-feeds/price-feed-ids.mdx @@ -0,0 +1,33 @@ +--- +title: Price Feed IDs +description: List of price feed IDs for all the assets supported by Pyth Core +slug: /price-feeds/core/price-feeds/price-feed-ids +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Suspense } from "react"; +import { PriceFeedIdsCoreTable } from "../../../../../src/components/PriceFeedIdsCoreTable"; + +# Price Feed IDs + +The following table lists the price feed IDs for all the assets supported by Pyth Core. + + + Pyth Core Price Feed IDs **are different** from Pyth Pro Price Feed IDs. + Please refer to the [Pyth Pro Price Feed IDs](/price-feeds/pro/price-feed-ids) + page for Pyth Pro Price Feed IDs. + + + +Developers using any of these testnets: + +- Aptos Testnet +- Sui Testnet +- Near Testnet + +Please use the **Beta** price feed IDs instead of the stable ones. + + + + + diff --git a/apps/developer-hub/content/docs/price-feeds/core/publish-data/confidence-interval-and-crypto-exchange-fees.mdx b/apps/developer-hub/content/docs/price-feeds/core/publish-data/confidence-interval-and-crypto-exchange-fees.mdx new file mode 100644 index 0000000000..d95a41df44 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/publish-data/confidence-interval-and-crypto-exchange-fees.mdx @@ -0,0 +1,26 @@ +--- +title: Confidence Interval and Crypto Exchange Fees +description: Learn how to calculate the confidence interval and crypto exchange fees +slug: /price-feeds/core/publish-data/confidence-interval-and-crypto-exchange-fees +--- + +It is very important that publishers consider crypto exchange aggressive fees when calculating their price and confidence intervals from one or more exchange order books. Ask prices should be moved up by the best publicly available aggressive fee rate, and bid prices should be moved down by the same rate. + +```sh copy +ask_adjusted = ask * (1.0 + fee_rate) +bid_adjusted = bid * (1.0 - fee_rate) +``` + +This is to reflect the "after fee" effective prices that could be gotten on that exchange. This is important for crypto markets because the fees are often MUCH larger than the typical bid-ask spread. It is not important for other markets (such as US equities) where fees are small compared with the bid-ask spread. The rationale for this adjustment is that the "fair price" could be above the best ask or below the best bid by as much as the aggressive fees before an informed trader would be able to profitably trade on this exchange and move the best price. Because of that, the best price on the exchange could be "wrong" by as much as +/- the aggressive fees. + +Example 1 - Exchange A has best aggressive fee of 10bps + +![](/images/Confidence_Interval_and_Crypto_Exchange_Fees_Table_1.png) + +Exchange A should publish a price of \$50,000.01 and a confidence of \$50.005 (half the bid-ask spread after fee adjustment). It would be wrong to publish a confidence of \$0.005 based on the "not fee-adjusted" raw exchange bid-ask spread. + +Example 2 - Exchange A has a best aggressive fee of 10bps. Exchange B has a best aggressive fee of 1bps, and a publisher is combining them into a single combined book. Exchange books are combined by taking the best ask across both exchanges and the best bid across both exchanges. + +![](/images/Confidence_Interval_and_Crypto_Exchange_Fees_Table_2.png) + +In this example, if a publisher were combining the books of Exchange A and Exchange B to get a combined price, they should publish a price of \$49,978.13 and confidence of \$28.125, which corresponds to the midprice and half the bid-ask spread of the combined fee-adjusted books. It would be wrong to publish a price of \$50,000.01 and confidence of \$0.01 based on the "not fee-adjusted" raw exchange prices. Note that in this example, not only is the confidence changed by including the exchange fees, but the price reported is also substantially different once fees are properly accounted for. diff --git a/apps/developer-hub/content/docs/price-feeds/core/publish-data/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/publish-data/index.mdx new file mode 100644 index 0000000000..0b0f608987 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/publish-data/index.mdx @@ -0,0 +1,72 @@ +--- +title: Publish Data +description: Learn how to publish data to the Pyth Network +slug: /price-feeds/core/publish-data +--- + +import { Step, Steps } from "fumadocs-ui/components/steps"; + +Data providers can get started publishing data to the Pyth Network by performing the following steps. + + + +## Request access + +First, contact the Pyth Data Association and request to become a data provider. +You can reach out on [Discord](https://discord.gg/Ff2XDydUhu) or [Telegram](https://t.me/Pyth_Network). +**Only data providers with first-party data (exchanges, market makers, and trading firms) are allowed to participate in the network.** + + + +## Generate keypair + +Every data provider is identified on the network by a public key, and their prices are signed by the corresponding private key. +You will need a Solana public/private key pair for this purpose. +If you do not already have a keypair, you can create one using the instructions below: + +```sh copy +# Install the Solana Tool Suite, needed for creating the key used to sign your transactions. +# See https://docs.solana.com/cli/install-solana-cli-tools for the latest version +sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" + +# Generate a public/private keypair. +solana-keygen new --no-bip39-passphrase --outfile publish_key_pair.json +``` + +This command will create a public/private keypair in `publish_key_pair.json`. +Please extract the public key from this file and share it with the Pyth Data Association so they can enable you to publish prices. + +```sh copy +# Print the public key of the keypair. +solana-keygen pubkey publish_key_pair.json +``` + +This command will output the public key in base58 encoding and will look something like: + +```sh copy +5rYvdyWAunZgD2EC1aKo7hQbutUUnkt7bBFM6xNq2z7Z +``` + +Most data providers choose to generate two separate keypairs, one for testing and one for production. +If you do so, please share both public keys with the Pyth Data Association. + + + +## Procure validators + +Every data provider to the network will require both a Solana RPC node and a Pythnet validator. +The Pyth Data Association will assist you with this step. + + + +## pyth-agent + +Data providers can publish data to the network using the [pyth-agent](https://github.com/pyth-network/pyth-agent) software package. +This package abstracts away all of the communication with the underlying blockchain and exposes a simple JSON RPC interface for submitting price data. +Please see the [README](https://github.com/pyth-network/pyth-agent) of that package for instructions on using it. +This software requires you to configure both the keypair and validators from the previous steps in order to run. +Please also see the [JSON RPC API documentation](publish-data/pyth-client-websocket-api.md). +Finally, the [example publisher](https://github.com/pyth-network/example-publisher) is a fully-worked example of how to integrate with the pyth-agent API. + + + diff --git a/apps/developer-hub/content/docs/price-feeds/core/publish-data/meta.json b/apps/developer-hub/content/docs/price-feeds/core/publish-data/meta.json index 625e66bae4..9b02adb945 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/publish-data/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/publish-data/meta.json @@ -1,8 +1,8 @@ { "pages": [ - "[Understanding Publishing Slots](./understanding-publishing-slots)", - "[pyth-client Websocket API](./pyth-client-websocket-api)", - "[Confidence Interval and Crypto Exchange Fees](./confidence-interval-and-crypto-exchange-fees)", - "[Useful Resources for Publishers](./useful-resources-for-publishers)" + "understanding-publishing-slots", + "pyth-client-websocket-api", + "confidence-interval-and-crypto-exchange-fees", + "useful-resources-for-publishers" ] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/publish-data/pyth-client-websocket-api.mdx b/apps/developer-hub/content/docs/price-feeds/core/publish-data/pyth-client-websocket-api.mdx new file mode 100644 index 0000000000..8c9cc96944 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/publish-data/pyth-client-websocket-api.mdx @@ -0,0 +1,280 @@ +--- +title: Pyth-Agent WebSocket API +description: Reference for publishing prices through the pyth-agent JSON-RPC WebSocket interface +slug: /price-feeds/core/publish-data/pyth-client-websocket-api +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +[`pyth-agent`](https://github.com/pyth-network/pyth-agent) exposes a WebSocket interface that follows the JSON-RPC 2.0 specification. The primary methods are: + +- [`get_product_list`](#get_product_list) +- [`update_price`](#update_price) +- [`subscribe_price_sched`](#subscribe_price_sched) +- [`get_product`](#get_product) +- [`get_all_products`](#get_all_products) + +Batch requests execute in the order submitted. **Batching is highly recommended when updating 50 or more price feeds.** + +## `get_product_list` + +Retrieve the list of available symbols and associated metadata. All attributes in the `attr_dict` dictionary are optional—clients should tolerate missing fields. + +**Request** + +```json copy +{ + "jsonrpc": "2.0", + "method": "get_product_list", + "id": 1 +} +``` + +**Response** + +```json copy +{ + "jsonrpc": "2.0", + "result": [ + { + "account": "9F6eBgAfktth93C9zmtKDXFXNjZkq6JwJR56VPKqWmJm", + "attr_dict": { + "symbol": "SYMBOL1/USD", + "asset_type": "Equity", + "country": "USA", + "description": "pyth example product #1", + "quote_currency": "USD", + "tenor": "Spot", + "cms_symbol": "SYMBOL1", + "cqs_symbol": "SYMBOL1", + "nasdaq_symbol": "SYMBOL1" + }, + "price": [ + { + "account": "CrZCEEt3awgkGLnVbsv45Pp4aLhr7fZfZr3ubzrbNXaq", + "price_exponent": -4, + "price_type": "price" + } + ] + } + ], + "id": null +} +``` + +## `update_price` + +Publish a price update using the signing key configured in `pyth-agent`. The `price` and `conf` parameters use fixed-point integers; apply the symbol’s exponent to derive decimal values. `status` can be `"trading"` or `"unknown"`. + +**Request** + +```json copy +{ + "jsonrpc": "2.0", + "method": "update_price", + "params": { + "account": "CrZCEEt3awgkGLnVbsv45Pp4aLhr7fZfZr3ubzrbNXaq", + "price": 42002, + "conf": 3, + "status": "trading" + }, + "id": 1 +} +``` + +**Response** + +```json copy +{ + "jsonrpc": "2.0", + "result": 0, + "id": 1 +} +``` + +## `subscribe_price_sched` + +Request notifications when it is time to submit the next price for a given symbol. + + + This method can saturate the link between the agent and the client. Implement + client-side scheduling or publish updates immediately when notified. + + +**Request** + +```json copy +{ + "jsonrpc": "2.0", + "method": "subscribe_price_sched", + "params": { + "account": "CrZCEEt3awgkGLnVbsv45Pp4aLhr7fZfZr3ubzrbNXaq" + }, + "id": 1 +} +``` + +**Subscription Response** + +```json copy +{ + "jsonrpc": "2.0", + "result": { + "subscription": 1234 + }, + "id": 1 +} +``` + +Subsequent notifications reference the subscription ID: + +```json copy +{ + "jsonrpc": "2.0", + "method": "notify_price_sched", + "params": { + "subscription": 1234 + } +} +``` + +## `get_product` + +Return detailed product information for a specific account. As with `get_product_list`, treat attributes as optional. + +**Request** + +```json copy +{ + "jsonrpc": "2.0", + "method": "get_product", + "params": { + "account": "4aDoSXJ5o3AuvL7QFeR6h44jALQfTmUUCTVGDD6aoJTM" + }, + "id": 1 +} +``` + +**Response** + +```json copy +{ + "jsonrpc": "2.0", + "result": { + "account": "4aDoSXJ5o3AuvL7QFeR6h44jALQfTmUUCTVGDD6aoJTM", + "attr_dict": { + "asset_type": "Crypto", + "symbol": "BTC/USD", + "country": "US", + "quote_currency": "USD", + "description": "BTC/USD", + "tenor": "Spot", + "generic_symbol": "BTCUSD" + }, + "price_accounts": [ + { + "account": "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU", + "price_type": "price", + "price_exponent": -8, + "status": "trading", + "price": 4426101900000, + "conf": 4271150000, + "ema_price": 4433467600000, + "ema_confidence": 1304202670, + "valid_slot": 91402257, + "pub_slot": 91402259, + "prev_slot": 91402256, + "prev_price": 4425895500000, + "prev_conf": 3315350000, + "publisher_accounts": [ + { + "account": "HekM1hBawXQu6wK6Ah1yw1YXXeMUDD2bfCHEzo25vnEB", + "status": "trading", + "price": 4426958500000, + "conf": 1492500000, + "slot": 91402255 + }, + { + "account": "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ", + "status": "trading", + "price": 4424690000000, + "conf": 3690000000, + "slot": 91402256 + } + ] + } + ] + }, + "id": 1 +} +``` + +## `get_all_products` + +Return full product data for every symbol. + +**Request** + +```json copy +{ + "jsonrpc": "2.0", + "method": "get_all_products", + "id": 1 +} +``` + +**Response** + +```json copy +{ + "jsonrpc": "2.0", + "result": [ + { + "account": "5uKdRzB3FzdmwyCHrqSGq4u2URja617jqtKkM71BVrkw", + "attr_dict": { + "asset_type": "Crypto", + "symbol": "BCH/USD", + "country": "US", + "quote_currency": "USD", + "description": "BCH/USD", + "tenor": "Spot", + "generic_symbol": "BCHUSD" + }, + "price_accounts": [ + { + "account": "5ALDzwcRJfSyGdGyhP3kP628aqBNHZzLuVww7o9kdspe", + "price_type": "price", + "price_exponent": -8, + "status": "trading", + "price": 60282000000, + "conf": 26000000, + "ema_price": 60321475000, + "ema_confidence": 22504746, + "valid_slot": 91402601, + "pub_slot": 91402604, + "prev_slot": 91402600, + "prev_price": 60282000000, + "prev_conf": 26000000, + "publisher_accounts": [ + { + "account": "HekM1hBawXQu6wK6Ah1yw1YXXeMUDD2bfCHEzo25vnEB", + "status": "trading", + "price": 60282000000, + "conf": 26000000, + "slot": 91402599 + }, + { + "account": "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6", + "status": "unknown", + "price": 0, + "conf": 0, + "slot": 0 + } + ] + } + ] + } + ], + "id": 1 +} +``` diff --git a/apps/developer-hub/content/docs/price-feeds/core/publish-data/understanding-publishing-slots.mdx b/apps/developer-hub/content/docs/price-feeds/core/publish-data/understanding-publishing-slots.mdx new file mode 100644 index 0000000000..577cc287ad --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/publish-data/understanding-publishing-slots.mdx @@ -0,0 +1,60 @@ +--- +title: Understanding Publishing Slots +description: Learn how publishing slots affect inclusion in aggregated Pyth prices +slug: /price-feeds/core/publish-data/understanding-publishing-slots +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +When a quoter publishes a price, the `pyth-client` API also forwards the current slot that it observes on Solana and Pythnet. This value is the publishing slot. + +The publishing slot and price is stored as the latest update for that publisher on-chain but only if the price is for a later slot than that currently stored. This is to prevent prices from being updated out-of-order and to facilitate arbitration between multiple publishers. + +The aggregation algorithm only combines prices from publishers that were published within 25 slots of the current on-chain slot. + +Not all published prices get included in the pyth contract due to unreliable transports and the way Solana and Pythnet formulate and reach consensus on each slot. + +A quoter may detect if a published price is dropped by comparing the list of publishing slots it submits vs what it subsequently receives in each aggregate price callback. + +For example, here is an excerpt of a log take from a run of the test_publish.cpp example program against mainnet-beta. It logs everything it sends and everything it receives. + +The publishing slots of six consecutive price submissions have been annotated with the labels A, B, C, D, E and F or slots 79018079, 79018084, 79018085, 79018086, 79018087, 79018092. + +The API submits a new price every time it receives notification of a new slot but note that prices for slots 79018080 thru 79018083 and 79018088 thru 79018091 were not submitted. This is because solana does not always publish consecutive slots and gaps can occur. Solana can also publish slots out-of-order, but the API ignores these and is guaranteed only to issue callbacks for slots that are strictly increasing. + +Price updates occur for slots labelled A, B, C and F. Slots D and E (79018086, 79018087) were dropped and did not get executed on the chain. + +```sh copy +[2021-05-18T22:36:14.048435Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.116000,spread=0.001000,slot=79018079,sub_id=1 + ^^ A ^^^ +[2021-05-18T22:36:14.237644Z 654359 INF received aggregate price update ] symbol=SYMBOL1/USD,price_type=price,status=trading,agg_price=0.112000,agg_spread=0.001000,valid_slot=79018076,pub_slot=79018077,my_price=0.112000,my_conf=0.001000,my_status=trading,my_slot=79018075 +[2021-05-18T22:36:14.405182Z 654359 INF received aggregate price update ] symbol=SYMBOL1/USD,price_type=price,status=trading,agg_price=0.113000,agg_spread=0.001000,valid_slot=79018077,pub_slot=79018078,my_price=0.113000,my_conf=0.001000,my_status=trading,my_slot=79018076 +[2021-05-18T22:36:16.099126Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.117000,spread=0.001000,slot=79018084,sub_id=1 + ^^ B ^^^ +[2021-05-18T22:36:16.962077Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.118000,spread=0.001000,slot=79018085,sub_id=1 + ^^ C ^^^ +[2021-05-18T22:36:17.519741Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.119000,spread=0.001000,slot=79018086,sub_id=1 + ^^ D ^^^ +[2021-05-18T22:36:17.671924Z 654359 INF received aggregate price update ] symbol=SYMBOL1/USD,price_type=price,status=trading,agg_price=0.114000,agg_spread=0.001000,valid_slot=79018078,pub_slot=79018079,my_price=0.114000,my_conf=0.001000,my_status=trading,my_slot=79018077 +[2021-05-18T22:36:18.109491Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.120000,spread=0.001000,slot=79018087,sub_id=1 + ^^ E ^^^ +[2021-05-18T22:36:20.537479Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.121000,spread=0.001000,slot=79018092,sub_id=1 + ^^ F ^^^ +[2021-05-18T22:36:21.195836Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.122000,spread=0.001000,slot=79018093,sub_id=1 +[2021-05-18T22:36:21.529074Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.123000,spread=0.001000,slot=79018094,sub_id=1 +[2021-05-18T22:36:21.802004Z 654359 INF received aggregate price update ] symbol=SYMBOL1/USD,price_type=price,status=trading,agg_price=0.116000,agg_spread=0.001000,valid_slot=79018079,pub_slot=79018085,my_price=0.116000,my_conf=0.001000,my_status=trading,my_slot=79018079 + ^^ A ^^^ +[2021-05-18T22:36:21.969477Z 654359 INF received aggregate price update ] symbol=SYMBOL1/USD,price_type=price,status=trading,agg_price=0.117000,agg_spread=0.001000,valid_slot=79018085,pub_slot=79018087,my_price=0.117000,my_conf=0.001000,my_status=trading,my_slot=79018084 + ^^ B ^^^ +[2021-05-18T22:36:22.304469Z 654359 INF received aggregate price update ] symbol=SYMBOL1/USD,price_type=price,status=trading,agg_price=0.118000,agg_spread=0.001000,valid_slot=79018087,pub_slot=79018093,my_price=0.118000,my_conf=0.001000,my_status=trading,my_slot=79018085 + ^^ C ^^^ +[2021-05-18T22:36:22.758348Z 654359 INF submit price to block-chain ] symbol=SYMBOL1/USD,price_type=price,price=0.125000,spread=0.001000,slot=79018096,sub_id=1 +[2021-05-18T22:36:23.121339Z 654359 INF received aggregate price update ] symbol=SYMBOL1/USD,price_type=price,status=trading,agg_price=0.121000,agg_spread=0.001000,valid_slot=79018093,pub_slot=79018094,my_price=0.121000,my_conf=0.001000,my_status=trading,my_slot=79018092 + ^^ F ^^^ +``` + +The API keeps track of the "hit-rate" of price submissions that show up in the update callbacks and tracks end-to-end latency statistics at the 25th, 50th, 75th and 99th percentiles both in terms of seconds of elapsed time and in number of slot updates observed. For example, from the same log: + +```sh copy +[2021-05-18T22:37:26.685518Z 654359 INF publish statistics ] symbol=SYMBOL1/USD,price_type=price,num_sent=135,hit_rate=73.333333,secs_p25=2.000000,secs_p50=2.500000,secs_p75=3.000000,secs_p99=7.500000,slot_p25=4,slot_p50=4,slot_p75=6,slot_p99=16 +``` diff --git a/apps/developer-hub/content/docs/price-feeds/core/publish-data/useful-resources-for-publishers.mdx b/apps/developer-hub/content/docs/price-feeds/core/publish-data/useful-resources-for-publishers.mdx new file mode 100644 index 0000000000..5715fb9bd4 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/publish-data/useful-resources-for-publishers.mdx @@ -0,0 +1,13 @@ +--- +title: Useful Resources for Publishers +description: Useful resources for publishers to analyse, monitor and review their price data +slug: /price-feeds/core/publish-data/useful-resources-for-publishers +--- + +This page contains useful tools for publishers to analyse, monitor and review their price data. + +- [Price Monitoring & Alerting Script](https://github.com/pyth-network/publisher-utils#monitoring): This monitoring script will provide alerts if a publishers data activity is suspicious i.e. price deviation, bad confidence interval +- [Pyth Price Feeds & Metrics](https://pyth.network/price-feeds): Publishers can review their price data metrics for permissioned symbols. The conformance logs that can be downloaded contain useful metrics that show publisher uptime, price deviations and alerts. The metrics page can be accessed by selecting the environment > symbol > publisher key tab +- [Pyth Publisher Ranking Page](https://insights.pyth.network/publishers): This page provides a full breakdown of publisher ranking and inactive/active price feeds +- [Pyth Agent API GitHub Repository](https://github.com/pyth-network/pyth-agent): This repository contains the latest release for the Pyth-Agent API +- [Solana Explorer](https://explorer.solana.com): Solana Explorer allows publishers to monitor their public keys balance and transactions. It also provides live cluster statistics. For Pythnet or Pythtest, publishers should select 'Custom RPC URL' and add the the RPC http URL diff --git a/apps/developer-hub/content/docs/price-feeds/core/pull-updates.mdx b/apps/developer-hub/content/docs/price-feeds/core/pull-updates.mdx new file mode 100644 index 0000000000..e08afa4422 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/pull-updates.mdx @@ -0,0 +1,58 @@ +--- +title: What is a Pull Oracle? +description: Learn how Pyth's pull oracle model differs from traditional push oracles +slug: /price-feeds/core/pull-updates +--- + +Most oracles today are push oracles where the oracle operator is responsible for submitting price updates to the blockchain. +Pyth is different: it is a _pull oracle_ where anyone can permissionlessly update the on-chain price. +This document explains the differences between push and pull oracles. + +## Push Oracles + +_Push oracles_ periodically update an on-chain price based on external trigger conditions. +The oracle has a smart contract that stores the current price. +The contract also has a set of permissioned operators who are authorized to update the price. +The oracle operators then commit to updating the on-chain price at a specific cadence, for example, once every 30 minutes or if the price moves by 1%. +Thus, in a push oracle, the on-chain price is periodically updated, regardless of whether or not anyone is using it. + +## Pull Oracles + +In contrast to push oracles, _pull oracles_ only update the on-chain price when requested. +There are different ways for users to request an updated price from a pull oracle. +Some pull oracles respond to on-chain requests: applications send one transaction to request data from the oracle, which then submits the response in a second transaction. +Pyth uses a simpler system where users can request the latest price update from an off-chain service. +Anyone can submit a price update to the on-chain Pyth contract, which verifies its authenticity and stores it for later use. +This system allows applications to use a single transaction flow that first updates the price then performs the necessary application logic. + +For a more in-depth explanation on the differences between push and pull oracles, refer to the following video tutorial: +[How to Build with Pyth's Pull Oracle Design: Pyth Tutorials](https://youtu.be/qdwrs23Qc9g) + +## Comparing Push and Pull + +![](/images/Push-vs-Pull-Oracle.jpg) + +Push and pull oracles differ on a number of important dimensions: + +- **Update frequency** -- In a push oracle, every price feed updates at a fixed update frequency. + The oracle operator determines the frequency, but it typically ranges from every 10 minutes to 1 hour. + In contrast, pull oracles can update at a much higher frequency. + For example, every Pyth price feed updates every 400 milliseconds. +- **Latency** -- An oracle's update frequency also affects its prices' latency. + The higher update frequencies of pull oracles allow applications to access lower-latency data. +- **Blockchain support** -- Pull oracles support a wide variety of different blockchains. + Push oracles typically support a smaller number of blockchains, as each additional chain requires ongoing gas expenditures. +- **Price feed selection** -- Similar to the item above, pull oracles also support a wide selection of price feeds. + In contrast, push oracles typically have a more limited selection. + Push oracles generally cannot support a wide selection of feeds due to the gas cost of periodically updating each feed. + +A fundamental reason for these differences is that push oracles incur gas costs for price updates. +These gas costs limit their scalability across all of the dimensions above. + +### Integration Differences + +Push oracles and pull oracles require applications to integrate in different ways. +With a push oracle, applications typically read the current price out of a smart contract. +Since the push oracle periodically updates the price, the application can assume the data in the smart contract is (reasonably) fresh. +With a pull oracle, applications need to update the on-chain price before reading it. +Developers using Pyth can refer to [How to Use Real-Time Price Data](/price-feeds/use-real-time-data) to learn how to perform these steps. diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/aptos.mdx b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/aptos.mdx new file mode 100644 index 0000000000..c5672b6bdc --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/aptos.mdx @@ -0,0 +1,18 @@ +--- +title: on Aptos +description: List of Push Feeds on Aptos +slug: /price-feeds/core/push-feeds/aptos +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { SponsoredFeedsTable } from "../../../../../src/components/SponsoredFeedsTable"; +import aptosMainnet from "./data/aptos/aptos-mainnet.json"; + +## Aptos Mainnet + + + If you would like to see additional feeds on this list, please fill in this + [form](https://tally.so/r/nGz2jj) to signal your interest. + + + diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/aptos/aptos-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/aptos/aptos-mainnet.json new file mode 100644 index 0000000000..8e66849fac --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/aptos/aptos-mainnet.json @@ -0,0 +1,179 @@ +{ + "feeds": [ + { + "alias": "APT/USD", + "id": "03ae4db29ed4ae33d323568895aa00337e658e348b37509f5372ae51f0af00d5", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BTC/USD", + "id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "ETH/USD", + "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SOL/USD", + "id": "ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "id": "2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USD1/USD", + "id": "0a2425d43486780990d8b63543029e20556be51fd756cca584212f4d539611d4", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "CAKE/USD", + "id": "2356af9529a1064d41e32d617e2ce1dca5733afa901daba9e2b68dee5d53ecf9", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SUI/USD", + "id": "23d7315113f5b1d3ba7a83604c44b94d79f4fd69af77f804fc7f920a6dc65744", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "STAPT/APT.RR", + "id": "2f218a73fb0c46ae8f9f7bb70ffbb232dd0dd65169b6401bfdc9bfb340a66b1a", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "AMI/USD", + "id": "9074ab34363ea1aada15db169f4678c10117e48f1ad1a8ba9f69c2a939c3a377", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SUSDE/USDE.RR", + "id": "271c64ce459937abf721d42552035713b6c58f80eeceab716a624607fda4b10f", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "CETUS/USD", + "id": "e5b274b2611143df055d6e7cd8d93fe1961716bcd4dca1cad87a83bc1e78c1ef", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BNB/USD", + "id": "2f95862b045670cd22bee3114c39763a4a08beeb663b145d283c31d7d1101c4f", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "WBTC/USD", + "id": "c9d8b075a5c69303365ae23633d4e085199bf5c520a3b90fed1322a0342ffc33", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "THL/USD", + "id": "74e3fbb0d33e0ed8c0078b56134dcebdae38852f0858a8ea4de4c5ea7474bd42", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDY/USD", + "id": "e393449f6aff8a4b6d3e1165a7c9ebec103685f3b41e60db4277b5b6d10e7326", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "WETH/USD", + "id": "9d4294bbcd1174d6f2003ec365831e64cc31d9f6f15a2b85399db8d5000960f6", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "THAPT/USD", + "id": "b29276972267db5d64ae718fb7f107ad9e72a79cabf9992f0e9bc75ad451a7f6", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "STONE/USD", + "id": "4dcc2fb96fb89a802ef9712f6bd2246d3607cf95ca5540cb24490d37003f8c46", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SUSDE/USD", + "id": "ca3ba9a619a4b3755c10ac7d5e760275aa95e9823d38a84fedd416856cdba37c", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDE/USD", + "id": "6ec879b1e9963de5ee97e9c8710b742d6228252a5e2ca12d4ae81d7fe5ee8c5d", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "STHAPT/THAPT.RR", + "id": "ea07fce25d7d716fe6ad10b267451011baadc8f3724b28487026072ddce3ba1b", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "RION/USD", + "id": "2d8b864599418dc83cb33fe1d91f69e90c8c1c32123d74211950f52a5cef006a", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "KAPT/USD", + "id": "a44d307a13145b84938740c93155fbea926e9fbdd46d50b67859b8fc47552959", + "time_difference": 15, + "price_deviation": 0.5, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/abstract-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/abstract-mainnet.json new file mode 100644 index 0000000000..d332c4077a --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/abstract-mainnet.json @@ -0,0 +1,32 @@ +{ + "feeds": [ + { + "alias": "WETH/USD", + "id": "9d4294bbcd1174d6f2003ec365831e64cc31d9f6f15a2b85399db8d5000960f6", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "id": "2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "PENGU/USD", + "id": "bed3097008b9b5e3c93bec20be79cb43986b85a996475589351a21e67bae9b61", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/arbitrum-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/arbitrum-mainnet.json new file mode 100644 index 0000000000..36c1e285ea --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/arbitrum-mainnet.json @@ -0,0 +1,32 @@ +{ + "feeds": [ + { + "alias": "HLP0/USDC.RR", + "id": "aa388e24e74d5dd12145f74fad3180266f78ed08c0a2f47c60583fdb612587ba", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USR/USD.RR", + "id": "512a79cc65f49531f0bbb72956353e79ecdc1e4a6e5241847196c1f9a11d8a52", + "time_difference": 21600, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "WSTUSR/USR.RR", + "id": "b74c2bc175c2dab850ce5a5451608501c293fe8410cb4aba7449dd1c355ab706", + "time_difference": 21600, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "RLP/USD.RR", + "id": "796bcb684fdfbba2b071c165251511ab61f08c8949afd9e05665a26f69d9a839", + "time_difference": 21600, + "price_deviation": 0.5, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/avalanche-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/avalanche-mainnet.json new file mode 100644 index 0000000000..29dbab8f92 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/avalanche-mainnet.json @@ -0,0 +1,11 @@ +{ + "feeds": [ + { + "alias": "HLP0/USDC.RR", + "id": "aa388e24e74d5dd12145f74fad3180266f78ed08c0a2f47c60583fdb612587ba", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/base-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/base-mainnet.json new file mode 100644 index 0000000000..9fca14291e --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/base-mainnet.json @@ -0,0 +1,88 @@ +{ + "feeds": [ + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "ETH/USD", + "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WETH/USD", + "id": "9d4294bbcd1174d6f2003ec365831e64cc31d9f6f15a2b85399db8d5000960f6", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "CBETH/USD", + "id": "15ecddd26d49e1a8f1de9376ebebc03916ede873447c1255d2d5891b92ce5717", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTETH/USD", + "id": "6df640f3b8963d8f8358f791f352b8364513f6ab1cca5ed3f1f7b5448980e784", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "SUI/USD", + "id": "23d7315113f5b1d3ba7a83604c44b94d79f4fd69af77f804fc7f920a6dc65744", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "XRP/USD", + "id": "ec5d399846a9209f3fe5881d70aae9268c94339ff9817e8d18ff19fa05eea1c8", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USR/USD", + "id": "10b013adec14c0fe839ca0fe54cec9e4d0b6c1585ac6d7e70010dac015e57f9c", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USR/USD.RR", + "id": "512a79cc65f49531f0bbb72956353e79ecdc1e4a6e5241847196c1f9a11d8a52", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "RLP/USD", + "id": "7265d5cf8ee0e7b5266f75ff19c42c5b7697a9756c9304aa78b6be4fbb8d823d", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "RLP/USD.RR", + "id": "796bcb684fdfbba2b071c165251511ab61f08c8949afd9e05665a26f69d9a839", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTUSR/USR.RR", + "id": "b74c2bc175c2dab850ce5a5451608501c293fe8410cb4aba7449dd1c355ab706", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/berachain-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/berachain-mainnet.json new file mode 100644 index 0000000000..8503e72086 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/berachain-mainnet.json @@ -0,0 +1,67 @@ +{ + "feeds": [ + { + "alias": "BERA/USD", + "id": "962088abcfdbdb6e30db2e340c8cf887d9efb311b1f2f17b155a63dbb6d40265", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "BTC/USD", + "id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "ETH/USD", + "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "id": "2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "PYUSD/USD", + "id": "c1da1b73d7f01e7ddd54b3766cf7fcd644395ad14f70aa706ec5384c59e76692", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "SUSDE/USDE.RR", + "id": "271c64ce459937abf721d42552035713b6c58f80eeceab716a624607fda4b10f", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "HONEY/USD", + "id": "f67b033925d73d43ba4401e00308d9b0f26ab4fbd1250e8b5407b9eaade7e1f4", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "HONEY/USD.RR", + "id": "8bb3695875f9c33594097b0e0a1daa881aa81290088f0eac3a07b700fc7612ba", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/ethereum-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/ethereum-mainnet.json new file mode 100644 index 0000000000..ea24a28f4f --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/ethereum-mainnet.json @@ -0,0 +1,46 @@ +{ + "feeds": [ + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 3600, + "price_deviation": 2, + "confidence_ratio": 100 + }, + { + "alias": "USR/USD", + "id": "10b013adec14c0fe839ca0fe54cec9e4d0b6c1585ac6d7e70010dac015e57f9c", + "time_difference": 3600, + "price_deviation": 2, + "confidence_ratio": 100 + }, + { + "alias": "WSTUSR/USR", + "id": "b74c2bc175c2dab850ce5a5451608501c293fe8410cb4aba7449dd1c355ab706", + "time_difference": 3600, + "price_deviation": 2, + "confidence_ratio": 100 + }, + { + "alias": "USDTB/NAV", + "id": "967549f1ff4869f41cb354a7116b9e5a9a3091bebe0b2640eeed745ca1f7f90b", + "time_difference": 3600, + "price_deviation": 2, + "confidence_ratio": 100 + }, + { + "alias": "LINEA/USD", + "id": "49e50653755fbf8018ab65a07be2f208ac8c4bdfc43200934304ca17ee663cab", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "BOLD/USD", + "id": "d6134dbb0427240f901e3e596d6e63f7d85088f96cd4cd4ae2f89c0819b5d623", + "time_difference": 3600, + "price_deviation": 0.5, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/hyperevm-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/hyperevm-mainnet.json new file mode 100644 index 0000000000..374c8aad2f --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/hyperevm-mainnet.json @@ -0,0 +1,305 @@ +{ + "feeds": [ + { + "alias": "BTC/USD", + "id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "ETH/USD", + "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "id": "2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "HYPE/USD", + "id": "4279e31cc369bbcc2faf022b382b080e32a8e689ff20fbc530d2a603eb6cd98b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTETH/USD", + "id": "6df640f3b8963d8f8358f791f352b8364513f6ab1cca5ed3f1f7b5448980e784", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTETH/STETH.RR", + "id": "f59ead01ed0faba85332a1e2feae8ddb14a1c94ebac259f1c982c92fc7ce333e", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WBTC/USD", + "id": "c9d8b075a5c69303365ae23633d4e085199bf5c520a3b90fed1322a0342ffc33", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WETH/USD", + "id": "9d4294bbcd1174d6f2003ec365831e64cc31d9f6f15a2b85399db8d5000960f6", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDE/USD", + "id": "6ec879b1e9963de5ee97e9c8710b742d6228252a5e2ca12d4ae81d7fe5ee8c5d", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "SUSDE/USD", + "id": "ca3ba9a619a4b3755c10ac7d5e760275aa95e9823d38a84fedd416856cdba37c", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "SUSDE/USDE.RR", + "id": "271c64ce459937abf721d42552035713b6c58f80eeceab716a624607fda4b10f", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTHYPE/STHYPE.RR", + "id": "1a78b5829a99f1d2897917dae2a02266c0210535a995a2e9d0692613bbc89e27", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "LHYPE/USD", + "id": "9e3cadc2a8a0ebfd765b34d5ee5de77a4add3114672fc0b8d3ad09ac56940069", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "FHYPE/HYPE.RR", + "id": "8f749681c078ce4ef65cd220994f25735b80264fca4386dd57b31eacf7e4610b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDXL/USD", + "id": "e10593860e9ee1c204e4f9569e877502f098dd1a4d84cc5bad06f23f77dcbfe2", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "MHYPE/HYPE.RR", + "id": "e35aebd2d35795acaa2b0e59f3b498510e8ef334986d151d1502adb9e26234f7", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "FEUSD/USD", + "id": "7f2e9a7365eb634c543e9ca72683a9cf778cdc16ee5b8bca73abe6d08c1410d5", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "MHYPE/USD", + "id": "a7fb4cdafed5130e8731b8da7c9208881f24e9b671bb92438b1fbf361d578112", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "STHYPE/USD", + "id": "068cd0617cbdd1dda615ed2b5ab4fe07d2e9f46347f5e785484844aa10d22dc5", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "UETH/USD", + "id": "08c73e187b45ecb2ab8375b975865d3c4a225fef1ccc7f326ad6eec66a24567a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "UBTC/USD", + "id": "42bfb26778f3504a9f359a92c731f77d0c24aed9b7745276e3ad0c2d840b74c2", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "CMETH/METH.RR", + "id": "cef5ad3be493afef85e77267cb0c07d048f3d54055409a34782996607e48cf0a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "METH/ETH.RR", + "id": "ee279eeb2fec830e3f535ad4d6524eb35eb1c6890cb1afc0b64554d08c88727e", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USR/USD.RR", + "id": "512a79cc65f49531f0bbb72956353e79ecdc1e4a6e5241847196c1f9a11d8a52", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USOL/USD", + "id": "974c7a77dbace44d229be17fc176975e06404b004476aeaff37641818cb0c55a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "BUDDY/USD", + "id": "ac2adf4571a391da22a2d39e8c5eb32ceecd6ab38c386a9194d669deece74dee", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "XAU/USD", + "id": "765d2ba906dbc32ca17cc11f5310a89e9ee1f6420508c63861f2f8ba4ee34bb2", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDHL/USD", + "id": "1497fb795ae65533d36d147b1b88c8b7226866a201589904c13acd314f694799", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "UFART/USD", + "id": "a210f55ff119d315002b5dc4f763b4e4114197028e45d6aca16498ab1433fb6d", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USH/USD", + "id": "eaa30c1ef2d9f4fde45d6e699bfda5187b3de200ea4cbab25d676b260ab728c1", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "HWHLP/USDC", + "id": "d136d4fd8d5f41c42339bcaf79954cfc2d50a33b129a990f8a2087d73cadade9", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WHLP/USDC", + "id": "b94c49af07479932872c63126f6bdee78140be7a953435e3815c8e1b204a0a04", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "STLOOP/LOOP", + "id": "1d99073631da1f959284bae0be4d027cfd41c98f4b6a95d20ccf4208a3a4b1f1", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "HLP0/USDC.RR", + "id": "aa388e24e74d5dd12145f74fad3180266f78ed08c0a2f47c60583fdb612587ba", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "KHYPE/HYPE.RR", + "id": "983b7cabc6fab548e15a5b05500da9b99c1682107b3e2ff289344116c10ac02c", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTUSR/USR.RR", + "id": "b74c2bc175c2dab850ce5a5451608501c293fe8410cb4aba7449dd1c355ab706", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "RLP/USD.RR", + "id": "796bcb684fdfbba2b071c165251511ab61f08c8949afd9e05665a26f69d9a839", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "KHYPE/USD", + "id": "2837a61ae8165c018b0e406ac32b1527270e57b81f0069260afbef71b9cf8ffe", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "HAHYPE/HYPE.RR", + "id": "19aec77cb70be18c66df7afd33da651d7b376fd26f7c06f2e8b77536c820a281", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "APE/USD", + "id": "15add95022ae13563a11992e727c91bdb6b55bc183d9d747436c80a483d8c864", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDH/USD", + "id": "f364e785775b4cb2f159ea823f8b5b9b669a4c221a3f845e518ba0e09611c553", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "THBILL/USDC.RR", + "id": "5b1bc5a579deba54dbaa9bc1c5b2e2b3f116d8d5ec27fbb3b9dc140a78e9f1e2", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/linea-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/linea-mainnet.json new file mode 100644 index 0000000000..43833dcdf4 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/linea-mainnet.json @@ -0,0 +1,18 @@ +{ + "feeds": [ + { + "alias": "REX33/USD", + "id": "583015352f5936e099fa7149d496ac087c5bfbfc386ce875be27dc4d69c2e023", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "LINEA/USD", + "id": "49e50653755fbf8018ab65a07be2f208ac8c4bdfc43200934304ca17ee663cab", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/soneium-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/soneium-mainnet.json new file mode 100644 index 0000000000..83cf5e2efe --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/soneium-mainnet.json @@ -0,0 +1,25 @@ +{ + "feeds": [ + { + "alias": "USR/USD.RR", + "id": "512a79cc65f49531f0bbb72956353e79ecdc1e4a6e5241847196c1f9a11d8a52", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "RLP/USD.RR", + "id": "796bcb684fdfbba2b071c165251511ab61f08c8949afd9e05665a26f69d9a839", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTUSR/USR.RR", + "id": "b74c2bc175c2dab850ce5a5451608501c293fe8410cb4aba7449dd1c355ab706", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/sonic-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/sonic-mainnet.json new file mode 100644 index 0000000000..c207874392 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/evm/sonic-mainnet.json @@ -0,0 +1,109 @@ +{ + "feeds": [ + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "ETH/USD", + "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WETH/USD", + "id": "9d4294bbcd1174d6f2003ec365831e64cc31d9f6f15a2b85399db8d5000960f6", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WBTC/USD", + "id": "c9d8b075a5c69303365ae23633d4e085199bf5c520a3b90fed1322a0342ffc33", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "BTC/USD", + "id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "id": "2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "S/USD", + "id": "f490b178d0c85683b7a0f2388b40af2e6f7c90cbe0f96b31f315f08d0e5a2d6d", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTKSCETH/SCETH.RR", + "id": "b680422b70915df562e4802bd8679112ff0f6b0a29ec2c3762ae2720eda01e58", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTKSCUSD/SCUSD.RR", + "id": "caed0964240861da425cf03fae9737473f6f031fb80cbbd73c3fb8cddd7a2204", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "STS/S.RR", + "id": "3b14bd355f182fa3a3feeea6824228e1f71e7c221a37bc91e8307280aee6a803", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "ANON/USD", + "id": "7a36855b8a4a6efd701ed82688694bbf67602de9faae509ae28f91065013cb82", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "GOGLZ/USD", + "id": "82465d1155ddbb2c73bf3491457163000f8e8d02dea90c548b1b7e56ae9fe4b1", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "SHADOW/USD", + "id": "6f02ad2b8a307411fc3baedb9876e83efe9fa9f5b752aab8c99f4742c9e5f5d5", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "STS/USD", + "id": "19f463beb47cb398cf2e2c8037f1d0073583cf18209c91a636f051d755ce0662", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "HLP0/USDC.RR", + "id": "aa388e24e74d5dd12145f74fad3180266f78ed08c0a2f47c60583fdb612587ba", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/movement/movement-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/movement/movement-mainnet.json new file mode 100644 index 0000000000..b001824615 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/movement/movement-mainnet.json @@ -0,0 +1,165 @@ +{ + "feeds": [ + { + "alias": "MOVE/USD", + "id": "6bf748c908767baa762a1563d454ebec2d5108f8ee36d806aadacc8f0a075b6d", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "APT/USD", + "id": "03ae4db29ed4ae33d323568895aa00337e658e348b37509f5372ae51f0af00d5", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "id": "2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "SUSDE/USD", + "id": "ca3ba9a619a4b3755c10ac7d5e760275aa95e9823d38a84fedd416856cdba37c", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WETH/USD", + "id": "9d4294bbcd1174d6f2003ec365831e64cc31d9f6f15a2b85399db8d5000960f6", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "MOD/USD", + "id": "9a2a116d85a31d6f1bed19771105557276457094e31791a892758148aa54023d", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "THAPT/USD", + "id": "b29276972267db5d64ae718fb7f107ad9e72a79cabf9992f0e9bc75ad451a7f6", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "STHAPT/APT.RR", + "id": "ea07fce25d7d716fe6ad10b267451011baadc8f3724b28487026072ddce3ba1b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "FRXUSD/USD", + "id": "7c53208632935ba5122c3cf65a0f4b3e72ba4955b49ad6ba0acf3d9ba405aef3", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "LBTC/USD", + "id": "8f257aab6e7698bb92b15511915e593d6f8eae914452f781874754b03d0c612b", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "ETH/USD", + "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "BTC/USD", + "id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WBTC/USD", + "id": "c9d8b075a5c69303365ae23633d4e085199bf5c520a3b90fed1322a0342ffc33", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WSTETH/USD", + "id": "6df640f3b8963d8f8358f791f352b8364513f6ab1cca5ed3f1f7b5448980e784", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "SOLVBTC/USD", + "id": "f253cf87dc7d5ed5aa14cba5a6e79aee8bcfaef885a0e1b807035a0bbecc36fa", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "AVALON.USDA/USD", + "id": "37c307959acbb353e1451bcf7da9d305c8cb8d54c64353588aaf900ffcffdd7d", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WEETH/USD", + "id": "9ee4e7c60b940440a261eb54b6d8149c23b580ed7da3139f7f08f4ea29dad395", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "WEETH/ETH.RR", + "id": "343558e79f587e098c321218ecb34d031ba709ab3e84133126f3c98511b91f64", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "EZETH/USD", + "id": "06c217a791f5c4f988b36629af4cb88fad827b2485400a358f3b02886b54de92", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "RSETH/USD", + "id": "0caec284d34d836ca325cf7b3256c078c597bc052fbd3c0283d52b581d68d71f", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "MBTC/USD", + "id": "6665073f5bc307b97e68654ff11f3d8875abd6181855814d23ab01b8085c0906", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + }, + { + "alias": "USDE/USD", + "id": "6ec879b1e9963de5ee97e9c8710b742d6228252a5e2ca12d4ae81d7fe5ee8c5d", + "time_difference": 3600, + "price_deviation": 1, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/sui/sui-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/sui/sui-mainnet.json new file mode 100644 index 0000000000..d9eed24cc9 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/sui/sui-mainnet.json @@ -0,0 +1,256 @@ +{ + "feeds": [ + { + "alias": "AFSUI/USD", + "id": "17cd845b16e874485b2684f8b8d1517d744105dbb904eec30222717f4bc9ee0d", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "AUSD/USD", + "id": "d9912df360b5b7f21a122f15bdd5e27f62ce5e72bd316c291f7c86620e07fb2a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BLUE/USD", + "id": "04cfeb7b143eb9c48e9b074125c1a3447b85f59c31164dc20c1beaa6f21f2b6b", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BNB/USD", + "id": "2f95862b045670cd22bee3114c39763a4a08beeb663b145d283c31d7d1101c4f", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BTC/USD", + "id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BUCK/USD", + "id": "fdf28a46570252b25fd31cb257973f865afc5ca2f320439e45d95e0394bc7382", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "CETUS/USD", + "id": "e5b274b2611143df055d6e7cd8d93fe1961716bcd4dca1cad87a83bc1e78c1ef", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "DEEP/USD", + "id": "29bdd5248234e33bd93d3b81100b5fa32eaa5997843847e2c2cb16d7c6d9f7ff", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "DMC/USD", + "id": "8abfa63ae82ca2fbc271861375e497166d8792580fb7c2ffcf014d2a131433f0", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "DOGE/USD", + "id": "dcef50dd0a4cd2dcc17e45df1676dcb336a11a61c69df7a0299b0150c672d25c", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "ETH/USD", + "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "FDUSD/USD", + "id": "ccdc1a08923e2e4f4b1e6ea89de6acbc5fe1948e9706f5604b8cb50bc1ed3979", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "HAEDAL/USD", + "id": "e67d98cc1fbd94f569d5ba6c3c3c759eb3ffc5d2b28e64538a53ae13efad8fd1", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "HASUI/USD", + "id": "6120ffcf96395c70aa77e72dcb900bf9d40dccab228efca59a17b90ce423d5e8", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "HIPPO/USD", + "id": "f2c5249856da2fbe0221e163b3fed678dd6f76515ab933292dfb4f15a1de8f8c", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "IKA/USD", + "id": "2b529621fa6e2c8429f623ba705572aa64175d7768365ef829df6a12c9f365f4", + "time_difference": 60, + "price_deviation": 3, + "confidence_ratio": 100 + }, + { + "alias": "LBTC/USD", + "id": "8f257aab6e7698bb92b15511915e593d6f8eae914452f781874754b03d0c612b", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "LOFI/USD", + "id": "82eebc2c47490ba9c0f9bc35ea9fb57a7e2bbf69b84a04ea2a3525153b8090ea", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "MUSD/USD", + "id": "2ee09cdb656959379b9262f89de5ff3d4dfed0dd34c072b3e22518496a65249c", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "NAVX/USD", + "id": "88250f854c019ef4f88a5c073d52a18bb1c6ac437033f5932cd017d24917ab46", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "NS/USD", + "id": "bb5ff26e47a3a6cc7ec2fce1db996c2a145300edc5acaabe43bf9ff7c5dd5d32", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SCA/USD", + "id": "7e17f0ac105abe9214deb9944c30264f5986bf292869c6bd8e8da3ccd92d79bc", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SEND/USD", + "id": "7d19b607c945f7edf3a444289c86f7b58dcd8b18df82deadf925074807c99b59", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SOL/USD", + "id": "ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "STSUI/USD", + "id": "0b3eae8cb6e221e7388a435290e0f2211172563f94769077b7f4c4c6a11eea76", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SUI/USD", + "id": "23d7315113f5b1d3ba7a83604c44b94d79f4fd69af77f804fc7f920a6dc65744", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "TRX/USD", + "id": "67aed5a24fdad045475e7195c98a98aea119c763f272d4523f5bac93a4f33c2b", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "TURBOS/USD", + "id": "f9c2e890443dd995d0baafc08eea3358be1ffb874f93f99c30b3816c460bbac3", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDC/USD", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "id": "2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDY/USD", + "id": "e393449f6aff8a4b6d3e1165a7c9ebec103685f3b41e60db4277b5b6d10e7326", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "VSUI/USD", + "id": "57ff7100a282e4af0c91154679c5dae2e5dcacb93fd467ea9cb7e58afdcfde27", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "WAL/USD", + "id": "eba0732395fae9dec4bae12e52760b35fc1c5671e2da8b449c9af4efe5d54341", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "XAUM/USD.RR", + "id": "d7db067954e28f51a96fd50c6d51775094025ced2d60af61ec9803e553471c88", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "UP/USD", + "id": "c591a547856b091560b120ee14b165a84ca58eca23b2ab635df641340bde1f10", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "XRP/USD", + "id": "ec5d399846a9209f3fe5881d70aae9268c94339ff9817e8d18ff19fa05eea1c8", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/svm/fogo-testnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/svm/fogo-testnet.json new file mode 100644 index 0000000000..24f41143f0 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/svm/fogo-testnet.json @@ -0,0 +1,36 @@ +{ + "feeds": [ + { + "alias": "FOGO/USD", + "account_address": "BVbxoxUoiS7hDGbhr6WYQod2qQsxs4gjTqFB8LekW1yt", + "id": "d3cd2bae6315f4f940cbd3a4a915f675f8fba85e33bd6aa5f7b727a15a9c812f", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "fUSD/USD", + "account_address": "9BZ6ozhtcTRYYMCBDLfePaoNTdEzpgZR3p4pHdM3CrVf", + "id": "8d940f7b53df8dd4b3c33a84c3ba043214c3cdcd5243c03b7cb4b0b22746efd8", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDC/USD", + "account_address": "8mKftY1J7M9FhmUA5iPF49G4ptHeh7tk2f5hgPQHqJsK", + "id": "41f3625971ca2ed2263e78573fe5ce23e13d2558ed3f2e47ab0f84fb9e7ae722", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "account_address": "86rHPbbzG8rnh4cQownzRHj9kLM9xY3YsSQM5xddtBZ6", + "id": "1fc18861232290221461220bd4e2acd1dcdfbc89c84092c93c18bdc7756c1588", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/svm/solana-mainnet.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/svm/solana-mainnet.json new file mode 100644 index 0000000000..24ce656ff5 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/data/svm/solana-mainnet.json @@ -0,0 +1,364 @@ +{ + "feeds": [ + { + "alias": "SOL/USD", + "account_address": "7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE", + "id": "ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "MSOL/USD", + "account_address": "5CKzb9j4ChgLUt8Gfm5CNGLN6khXKiqMbnGAW4cgXgxK", + "id": "c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BSOL/USD", + "account_address": "5cN76Xm2Dtx9MnrQqBDeZZRsWruTTcw37UruznAdSvvE", + "id": "89875379e70f8fbadc17aef315adf3a8d5d160b811435537e03c97e8aac97d9c", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SSOL/SOL", + "account_address": "2doCYXwYNt2FhzfCdgpW4YAwczvdzB27xtJkzQd5Kre2", + "id": "add6499a420f809bbebc0b22fbf68acb8c119023897f6ea801688e0d6e391af4", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BONK/USD", + "account_address": "DBE3N8uNjhKPRHfANdwGvCZghWXyLPdqdSbEW2XFwBiX", + "id": "72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "W/USD", + "account_address": "BEMsCSQEGi2kwPA4mKnGjxnreijhMki7L4eeb96ypzF9", + "id": "eff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "MEW/USD", + "account_address": "EF6U755BdHMXim8RBw6XSC6Yk6XaouTKpwcBZ7QkcanB", + "id": "514aed52ca5294177f20187ae883cec4a018619772ddce41efcc36a6448f5d5d", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDC/USD", + "account_address": "Dpw1EAVrSB1ibxiDQyTAW6Zip3J4Btk2x4SgApQCeFbX", + "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BTC/USD", + "account_address": "4cSM2e6rvbGQUFiJbqytoVMi5GgghSMr8LwVrT9VPSPo", + "id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "USDT/USD", + "account_address": "HT2PLQBcG5EiCcNSaMHAjSgd9F98ecpATbk4Sk5oYuM", + "id": "2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "JUP/USD", + "account_address": "7dbob1psH1iZBS7qPsm3Kwbf5DzSXK8Jyg31CTgTnxH5", + "id": "0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "ETH/USD", + "account_address": "42amVS4KgzR9rA28tkVYqVXjq9Qa8dcZQMbH5EYFX6XC", + "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "PYTH/USD", + "account_address": "8vjchtMuJNY4oFQdTi8yCe6mhCaNBFaUbktT482TpLPS", + "id": "0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "HNT/USD", + "account_address": "4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33", + "id": "649fdd7ec08e8e2a20f425729854e90293dcbe2376abc47197a14da6ff339756", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "ORCA/USD", + "account_address": "4CBshVeNBEXz24GZpoj8SrqP5L7VGG3qjGd6tCST1pND", + "id": "37505261e557e251290b8c8899453064e8d760ed5c65a779726f2490980da74c", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SAMO/USD", + "account_address": "2eUVzcYccqXzsDU1iBuatUaDCbRKBjegEaPPeChzfocG", + "id": "49601625e1a342c1f90c3fe6a03ae0251991a1d76e480d2741524c29037be28a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "WIF/USD", + "account_address": "6B23K3tkb51vLZA14jcEQVCA1pfHptzEHFA93V5dYwbT", + "id": "4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54cd4cc61fc", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "INF/USD", + "account_address": "Ceg5oePJv1a6RR541qKeQaTepvERA3i8SvyueX9tT8Sq", + "id": "f51570985c642c49c2d6e50156390fdba80bb6d5f7fa389d2f012ced4f7d208f", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "MNDE/USD", + "account_address": "GHKcxocPyzSjy7tWApQjKRkDNuVXd4Kk624zhuaR7xhC", + "id": "3607bf4d7b78666bd3736c7aacaf2fd2bc56caa8667d3224971ebe3c0623292a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "NEON/USD", + "account_address": "F2VfCymdNQiCa8Vyg5E7BwEv9UPwfm8cVN6eqQLqXiGo", + "id": "d82183dd487bef3208a227bb25d748930db58862c5121198e723ed0976eb92b7", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "AUD/USD", + "account_address": "6pPXqXcgFFoLEcXfedWJy3ypNZVJ1F3mgipaDFsvZ1co", + "id": "67a6f93030420c1c9e3fe37c1ab6b77966af82f995944a9fefce357a22854a80", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "GBP/USD", + "account_address": "G25Tm7UkVruTJ7mcbCxFm45XGWwsH72nJKNGcHEQw1tU", + "id": "84c2dde9633d93d1bcad84e7dc41c9d56578b7ec52fabedc1f335d673df0a7c1", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "EUR/USD", + "account_address": "Fu76ChamBDjE8UuGLV6GP2AcPPSU6gjhkNhAyuoPm7ny", + "id": "a995d00bb36a63cef7fd2c287dc105fc8f3d93779f062f09551b0af3e81ec30b", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "XAG/USD", + "account_address": "H9JxsWwtDZxjSL6m7cdCVsWibj3JBMD9sxqLjadoZnot", + "id": "f2fb02c32b055c805e7238d628e5e9dadef274376114eb1f012337cabe93871e", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "XAU/USD", + "account_address": "2uPQGpm8X4ZkxMHxrAW1QuhXcse1AHEgPih6Xp9NuEWW", + "id": "765d2ba906dbc32ca17cc11f5310a89e9ee1f6420508c63861f2f8ba4ee34bb2", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "BLZE/USD", + "account_address": "FFv5yoCGhEgWv6mXhwv4KX8A2dYcVAzi88a6Yu8Tf3iB", + "id": "93c3def9b169f49eed14c9d73ed0e942c666cf0e1290657ec82038ebb792c2a8", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "JLP/USD", + "account_address": "2TTGSRSezqFzeLUH8JwRUbtN66XLLaymfYsWRTMjfiMw", + "id": "c811abc82b4bad1f9bd711a2773ccaa935b03ecef974236942cec5e0eb845a3a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "WBTC/USD", + "account_address": "9gNX5vguzarZZPjTnE1hWze3s6UsZ7dsU3UnAmKPnMHG", + "id": "c9d8b075a5c69303365ae23633d4e085199bf5c520a3b90fed1322a0342ffc33", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "PENGU/USD", + "account_address": "27zzC5wXCeZeuJ3h9uAJzV5tGn6r5Tzo98S1ZceYKEb8", + "id": "bed3097008b9b5e3c93bec20be79cb43986b85a996475589351a21e67bae9b61", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "TRUMP/USD", + "account_address": "9vNb2tQoZ8bB4vzMbQLWViGwNaDJVtct13AGgno1wazp", + "id": "879551021853eec7a7dc827578e8e69da7e4fa8148339aa0d3d5296405be4b1a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "FARTCOIN/USD", + "account_address": "2t8eUbYKjidMs3uSeYM9jXM9uudYZwGkSeTB4TKjmvnC", + "id": "58cd29ef0e714c5affc44f269b2c1899a52da4169d7acc147b9da692e6953608", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "ACRED/USD", + "account_address": "6gyQ2TKvvV1JB5oWDobndv6BLRWcJzeBNk9PLQ5uPQms", + "id": "40ac3329933a6b5b65cf31496018c5764ac0567316146f7d0de00095886b480d", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "PUMP/USD", + "account_address": "HMm3GPbdnqGwbkTnUUqCFsH8AMHDdEC3Lg8gcPD3HJSH", + "id": "7a01fca212788bba7c5bf8c9efd576a8a722f070d2c17596ff7bb609b8d5c3b9", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "JUPSOL/SOL.RR", + "account_address": "D7UqeBmCEmhGXGYfi2y9RfoCa7t1Xw5iZLBeYZ3sxFSe", + "id": "f8d8d6b6c866c8b2624fb5b679ae846738725e5fc887fa8e927c8d8645018a2b", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "NAV.USTB/USD", + "account_address": "EqggHKbjePzmXAX6MW3EsgjiJ4mhkbb8j5s5KfGs1gLq", + "id": "dea78edd10cd7ae4524cc1744216788746306623bc3553014eeab6062860795d", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "NAV.USCC/USD", + "account_address": "823Y4cV7XH2TzkB9NdHfTRoCKLrqXv8EgQP5nzEG43Hp", + "id": "5d73a5953dc86c4773adc778c30e8a6dfc94c5c3a74d7ebb56dd5e70350f044a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "WTIZ5/USD", + "account_address": "3MBVC4DW1KsJcH1CB61XNHMo7CPkKW21gFNUku1sJ33q", + "id": "0c62848c8afee091f2c132eef944e3075c6de476129efc872a4202d81ca34f99", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "ZBTC/USD", + "account_address": "7qFJxM2GefbY2td7cXb6bmXmwVqkeF7kYjaypgZWLBng", + "id": "3d824c7f7c26ed1c85421ecec8c754e6b52d66a4e45de20a9c9ea91de8b396f9", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "LBTC/USD", + "account_address": "HENev4WeM2VhJ2b9tFCQsWdHGU6fTvgW68MsvBeYpxYn", + "id": "8f257aab6e7698bb92b15511915e593d6f8eae914452f781874754b03d0c612b", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "INF/SOL", + "account_address": "4MbCk4vH47K2gHee6nTg62KScpGu2bV3YDeTZtpQm3ro", + "id": "49e50653755fbf8018ab65a07be2f208ac8c4bdfc43200934304ca17ee663cab", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "WTIX5/USD", + "account_address": "2SxsutiRd7TBmURrWW2tPR3xeHpJFuGVGAd4Wjddkk7D", + "id": "2e8c6b85cf4a79b6d8bce10be470eefb369810b642782cb6aa150f82362e65d1", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "INDEX.FORD/USD", + "account_address": "GUq4JEVMgC5AmZpKxjh1aJsabB9X7mBwPavKSsnz11DS", + "id": "84d8c84bfbe6f71af527493f9aaee09950ee3e09c8460b2b781ce65ea341c10a", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "INDEX.GLXY/USD", + "account_address": "84NBovYcdtTdbb9vw9U7YeGPssTuCxcAMexw3PWDzWhR", + "id": "c59735498fa594a63e36382c12656e4313a7269ea1a1ed8fa583008e277f9cdb", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "SYRUPUSDC/USDC.RR", + "account_address": "GWdwWDhYFUc8ZD6uCTtEAAwx97V1ZCsxPWGL7vhSha6w", + "id": "2ad31d1c4a85fbf2156ce57fab4104124c5ef76a6386375ecfc8da1ed5ce1486", + "time_difference": 60, + "price_deviation": 0.5, + "confidence_ratio": 100 + }, + { + "alias": "PST/USDC.RR", + "account_address": "CBGwQddTeYn3KdvxGWtU95fqCcavzHK9XPFBLENDF5JR", + "id": "675e36f84a6be779ed793c71eb5c03151e1866c125767f46933626e0610af84d", + "time_difference": 240, + "price_deviation": 0.05, + "confidence_ratio": 100 + } + ] +} diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/evm.mdx b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/evm.mdx new file mode 100644 index 0000000000..3373a21e6f --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/evm.mdx @@ -0,0 +1,97 @@ +--- +title: on EVM +description: List of Push Feeds on EVM networks +slug: /price-feeds/core/push-feeds/evm +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { SponsoredFeedsTable } from "../../../../../src/components/SponsoredFeedsTable"; +import abstractMainnet from "./data/evm/abstract-mainnet.json"; +import arbitrumMainnet from "./data/evm/arbitrum-mainnet.json"; +import avalancheMainnet from "./data/evm/avalanche-mainnet.json"; +import baseMainnet from "./data/evm/base-mainnet.json"; +import berachainMainnet from "./data/evm/berachain-mainnet.json"; +import ethereumMainnet from "./data/evm/ethereum-mainnet.json"; +import hyperevmMainnet from "./data/evm/hyperevm-mainnet.json"; +import lineaMainnet from "./data/evm/linea-mainnet.json"; +import soneiumMainnet from "./data/evm/soneium-mainnet.json"; +import sonicMainnet from "./data/evm/sonic-mainnet.json"; + +The following EVM chains have push feeds: + +- [Abstract Mainnet](#abstract-mainnet) +- [Arbitrum Mainnet](#arbitrum-mainnet) +- [Avalanche Mainnet](#avalanche-mainnet) +- [Base Mainnet](#base-mainnet) +- [Berachain Mainnet](#berachain-mainnet) +- [Ethereum Mainnet](#ethereum-mainnet) +- [HyperEVM Mainnet](#hyperevm-mainnet) +- [Linea Mainnet](#linea-mainnet) +- [Soneium Mainnet](#soneium-mainnet) +- [Sonic Mainnet](#sonic-mainnet) + + + If you would like to see additional feeds on this list, please fill in this + [form](https://tally.so/r/nGz2jj) to signal your interest. + + +## Abstract Mainnet + + + +## Arbitrum Mainnet + + + +## Avalanche Mainnet + + + +## Base Mainnet + + + +## Berachain Mainnet + + + +## Ethereum Mainnet + + + +## HyperEVM Mainnet + + + +## Linea Mainnet + + + +## Soneium Mainnet + + + +## Sonic Mainnet + + diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/fogo.mdx b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/fogo.mdx new file mode 100644 index 0000000000..c9afd07f0f --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/fogo.mdx @@ -0,0 +1,18 @@ +--- +title: on Fogo +description: List of Push Feeds on Fogo +slug: /price-feeds/core/push-feeds/fogo +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { SponsoredFeedsTable } from "../../../../../src/components/SponsoredFeedsTable"; +import fogoTestnet from "./data/svm/fogo-testnet.json"; + +## Fogo Testnet + + + If you would like to see additional feeds on this list, please fill in this + [form](https://tally.so/r/nGz2jj) to signal your interest. + + + diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/index.mdx new file mode 100644 index 0000000000..82652a08ab --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/index.mdx @@ -0,0 +1,41 @@ +--- +title: Push Feeds +description: See which Pyth price feeds receive sponsored push updates by network +slug: /price-feeds/core/push-feeds +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +The Pyth Data Association **pushes** price updates for various feeds on some networks. +These feeds are updated at a specific heartbeat rate or when the price changes by a specific percentage. +Applications can depend on receiving updates for these feeds, without having to pull them explicitly. + +The feeds can vary by network. Please see the relevant section below for the network of interest. + +- [EVM](/price-feeds/core/push-feeds/evm) +- [Solana](/price-feeds/core/push-feeds/solana) +- [Fogo](/price-feeds/core/push-feeds/fogo) +- [Aptos](/price-feeds/core/push-feeds/aptos) +- [Movement](/price-feeds/core/push-feeds/movement) +- [Sui](/price-feeds/core/push-feeds/sui) + + + Deviation thresholds can be customized to fit builders' needs, and additional + feeds can be requested for this list. If you need custom thresholds or would + like to see additional feeds, please fill in this + [form](https://tally.so/r/nGz2jj) to signal your interest. + + + + Push feeds are subject to change with prior notice. Please refer to the [dev- + forum](https://dev-forum.pyth.network/c/announcements/6) for the latest + changes. + + + + DISCLAIMER: While the Pyth Data Association strives to deliver timely updates, + these push feeds may occasionally experience delays in updates caused by chain + halts, gas estimations and other issues. Applications are advised to run their + own price-pusher. Find out how you can run your own price-pusher + [here](/price-feeds/core/schedule-price-updates/using-price-pusher). + diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/meta.json b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/meta.json index 47a53581a2..dc61d245e3 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/meta.json @@ -1,10 +1,5 @@ { - "pages": [ - "[EVM](./evm)", - "[Solana](./solana)", - "[Fogo](./fogo)", - "[Aptos](./aptos)", - "[Movement](./movement)", - "[Sui](./sui)" - ] + "title": "Push Feeds", + "pages": ["evm", "solana", "fogo", "aptos", "movement", "sui"], + "defaultOpen": false } diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/movement.mdx b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/movement.mdx new file mode 100644 index 0000000000..edfde8ccca --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/movement.mdx @@ -0,0 +1,21 @@ +--- +title: on Movement +description: List of Push Feeds on Movement +slug: /price-feeds/core/push-feeds/movement +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { SponsoredFeedsTable } from "../../../../../src/components/SponsoredFeedsTable"; +import movementMainnet from "./data/movement/movement-mainnet.json"; + +## Movement Mainnet + + + If you would like to see additional feeds on this list, please fill in this + [form](https://tally.so/r/nGz2jj) to signal your interest. + + + diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/solana.mdx b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/solana.mdx new file mode 100644 index 0000000000..12cb5be1ad --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/solana.mdx @@ -0,0 +1,23 @@ +--- +title: on Solana +description: List of Push Feeds on Solana +slug: /price-feeds/core/push-feeds/solana +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { SponsoredFeedsTable } from "../../../../../src/components/SponsoredFeedsTable"; +import solanaMainnet from "./data/svm/solana-mainnet.json"; + + + If you would like to see additional feeds on this list, please fill in this + [form](https://tally.so/r/nGz2jj) to signal your interest. + + +## Solana Mainnet + + + +Note: The addresses represent the price feed account for shard 0 of the relevant price feed id. diff --git a/apps/developer-hub/content/docs/price-feeds/core/push-feeds/sui.mdx b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/sui.mdx new file mode 100644 index 0000000000..27ee02afba --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/push-feeds/sui.mdx @@ -0,0 +1,18 @@ +--- +title: on Sui +description: List of Push Feeds on Sui +slug: /price-feeds/core/push-feeds/sui +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { SponsoredFeedsTable } from "../../../../../src/components/SponsoredFeedsTable"; +import suiMainnet from "./data/sui/sui-mainnet.json"; + + + If you would like to see additional feeds on this list, please fill in this + [form](https://tally.so/r/nGz2jj) to signal your interest. + + +## Sui Mainnet + + diff --git a/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/account-structure.mdx b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/account-structure.mdx new file mode 100644 index 0000000000..a536bddf62 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/account-structure.mdx @@ -0,0 +1,95 @@ +--- +title: Account Structure +description: Understand the layout of Pyth mapping, product, and price accounts +slug: /price-feeds/core/pythnet-reference/account-structure +--- + +The Pyth oracle program manages a number of on-chain accounts. There are three different types of accounts: + +1. _Product accounts_ store metadata about a product, such as its symbol (e.g., "BTC/USD") and asset type. +2. _Price accounts_ store the current price information for a particular product. This account has fields such as the current price, a confidence interval, an exponential moving average price, an exponential moving average confidence interval and whether or not a price is currently available. +3. _Mapping accounts_ serve as a listing of other accounts. The mapping accounts are organized into a linked list whose values are the set of product accounts. These accounts allow applications to enumerate the full list of products whose prices are available on Pyth. + +The [Pyth Rust SDK](https://github.com/pyth-network/pyth-sdk-rs) contains a sample application that prints the current content of all Pyth accounts. The following sections use the output of this application to better understand the content of these accounts. + +**Product Accounts** + +Product accounts store metadata about a product. This metadata is represented as a set of reference attributes, stored as a list of text key/value pairs. Not all product accounts follow the same structure; for a comprehensive overview, visit the [Product Metadata page](./product-metadata). For example, the product account for AAPL contains the following fields: + +```sh copy +product_account .. G89jkM5wFLpmnbvRbeePUumxsJyzoXaRfgBVjyx2CPzQ + symbol.......... Equity.US.AAPL/USD + asset_type...... Equity + quote_currency.. USD + description..... APPLE INC + base............ AAPL + country......... US + cms_symbol...... AAPL + cqs_symbol...... AAPL + nasdaq_symbol... AAPL + price_account... CqFJLrT4rSpA46RQkVYWn8tdBDuQ7p7RXcp6Um76oaph +``` + +This snippet shows the reference attributes for AAPL. The set of available reference attributes depends on the `asset_type`. Every product account has `symbol` , `asset_type`, `quote_currency` , and `price_account` . US equity products additionally include additional reference symbology that is useful for mapping Pyth products to other industry-standard identifiers. The product account also contains a pointer to a price account that contains the product's current pricing information. + +As another example, here is the product account for BTC/USD: + +```sh copy +product_account .. 3m1y5h2uv7EQL3KaJZehvAJa4yDNvgc5yAdL9KPMKwvk + symbol.......... Crypto.BTC/USD + asset_type...... Crypto + quote_currency.. USD + description..... BTC/USD + generic_symbol.. BTCUSD + base............ BTC + price_account .. HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J +``` + +**Price Accounts** + +Price accounts store the current price of a product along with additional useful information. For example, consider the following content of AAPL's price account: + +```sh copy +price_account .. CqFJLrT4rSpA46RQkVYWn8tdBDuQ7p7RXcp6Um76oaph + price ........ 16297000 x 10^-5 + conf ......... 27952 x 10^-5 + price_type ... price + exponent ..... -5 + status ....... trading + corp_act ..... nocorpact + num_qt ....... 2 + valid_slot ... 110430111 + publish_slot . 110430112 + ema_price ......... 16247409 x 10^-5 + ema_confidence ......... 19415 x 10^-5 +``` + +This account stores the current price in a fixed-point format. The price is computed by taking the `price` field and multiplying by `10^exponent`. The account also includes a confidence interval that represents Pyth's uncertainty about the current price. This confidence interval can be interpreted as the standard deviation of a Laplace distribution centered around the price. `conf` is also stored in the same fixed-point format. In the example above, the price is 12276250, the conf is 1500 and the exponent is -5. These values translate into a price of \$122.76250 +- 0.015. + +Price accounts include several other useful fields. First, each account has a `status` that indicates whether or not the price is valid. Pricing information for a product can be unavailable for various reasons, for example, US equity markets only trade during certain hours. The status field indicates whether or not Pyth currently has a price for the product. **Only prices with a value of `status=trading` should be used**. If the status is not `trading` but is Unknown, Halted or Auction the Pyth price can be an arbitrary value. + +**Mapping Accounts** + +Mapping accounts serve as an index of the pricing information currently available on Pyth. These accounts are organized into a linked list whose values are product accounts. Applications can traverse this linked list to enumerate all products currently available on Pyth. + +The on-chain relationship between different account types is as follows: + +``` + ------------- ------------- ------------- + | |1 m| | | | + | mapping |------->| product |------>| price | + | | | | | | + ------------- ------------- ------------- + | + V + ------------- + | | + | mapping | + | | + ------------- + | + V + ... +``` + +Each mapping account contains a list of product account ids, plus an optional pointer to the subsequent mapping account. Each product account in turn points to the price account that stores the current price information for that product. diff --git a/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/index.mdx new file mode 100644 index 0000000000..5338ae5446 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/index.mdx @@ -0,0 +1,11 @@ +--- +title: Pythnet Reference +description: Reference material for Pythnet accounts, product metadata, and schedule formats +slug: /price-feeds/core/pythnet-reference +--- + +Refer to the following resources for deeper details about the data structures used on Pythnet: + +- [Account Structure](/price-feeds/core/pythnet-reference/account-structure) +- [Product Metadata](/price-feeds/core/pythnet-reference/product-metadata) +- [Schedule Format](/price-feeds/core/pythnet-reference/schedule-format) diff --git a/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/meta.json b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/meta.json index 7ba3e930c2..960f51ca08 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/meta.json @@ -1,7 +1,5 @@ { - "pages": [ - "[Account Structure](./account-structure)", - "[Product Metadata](./product-metadata)", - "[Schedule Format](./schedule-format)" - ] + "title": "Pythnet Reference", + "pages": ["account-structure", "product-metadata", "schedule-format"], + "defaultOpen": false } diff --git a/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/product-metadata.mdx b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/product-metadata.mdx new file mode 100644 index 0000000000..6d4f84f2b0 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/product-metadata.mdx @@ -0,0 +1,127 @@ +--- +title: Product Metadata +description: Review the standard fields stored in Pyth product accounts by asset type +slug: /price-feeds/core/pythnet-reference/product-metadata +--- + +Product accounts store metadata about a product. This metadata is represented as a set of reference attributes, stored as a list of text key/value pairs but not all products share the same account structure. Metadata is network dependent. + +Every product has `product_account`, `symbol`, `asset_type`, `quote_currency`, `base` and `price_account`. However, the remaining fields of a product account will depend on its `asset_type`. + +**Equity** + +As a rule, all products with `asset_type` = Equity will follow the below Product Account structure: + +```sh copy +product_account... Solana Account + asset_type...... AssetType + base............ BaseCurrency + cms_symbol...... NYSESymbol + cqs_symbol...... SIPSSymbol + country......... Country + description..... Description + nasdaq_symbol... ComstockSymbol + quote_currency.. QuoteCurrency + symbol.......... AssetType.Country.BaseCurrency/QuoteCurrency + weekly_schedule. WeeklySchedule + price_account... Solana Account +``` + +`symbol`: AssetType.Country.BaseCurrency/QuoteCurrency where the `base`: BaseCurrency is, in order of availability: + +1. `cms_symbol`: NYSESymbol +2. `cqs_symbol`: SIPSSymbol +3. `nasdaq_symbol`: ComstockSymbol + +Here is a snapshot of the Apple product account on Pythnet: + +```sh copy +product_account .. 3mkwqdkawySvAm1VjD4f2THN5mmXzb76fvft2hWpAANo + asset_type...... Equity + base............ AAPL + cms_symbol...... AAPL + cqs_symbol...... AAPL + country......... US + description..... APPLE INC / US DOLLAR + nasdaq_symbol... AAPL + quote_currency.. USD + symbol.......... Equity.US.AAPL/USD + weekly_schedule. America/New_York,9:30-16:00,9:30-16:00,9:30-16:00,9:30-16:00,9:30-16:00,C,C + price_account... 5yixRcKtcs5BZ1K2FsLFwmES1MyA92d6efvijjVevQCw +``` + +**Crypto** + +As a rule, all products with `asset_type` = Crypto will follow the below Product Account structure: + +```sh copy +product_account .. Solana Account + asset_type...... AssetType + base............ BaseCurrency + description..... Description + generic_symbol.. JLQDSymbol + quote_currency.. QuoteCurrency + symbol.......... AssetType.BaseCurrency/QuoteCurrency + weekly_schedule. WeeklySchedule + price_account .. Solana Account +``` + +Here is a snapshot of the Ethereum product account on Pythnet: + +```sh copy +product_account .. EMkxjGC1CQ7JLiutDbfYb7UKb3zm9SJcUmr1YicBsdpZ + asset_type...... Crypto + base............ ETH + description..... ETHEREUM / US DOLLAR + generic_symbol.. ETHUSD + quote_currency.. USD + symbol.......... Crypto.ETH/USD + weekly_schedule. America/New_York,O,O,O,O,O,O,O + price_account .. JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB +``` + +**Foreign Currency & Metal** + +Lastly, are Foreign Currencies (FX) and Metal assets. Those 2 `asset_type` share a common product account structure that follows the below template: + +```sh copy +product_account .. Solana Account + asset_type...... AssetType + base............ BaseCurrency + description..... Description + generic_symbol.. JLQDSymbol + quote_currency.. QuoteCurrency + symbol.......... AssetType.BaseCurrency/QuoteCurrency + tenor........... Maturity + weekly_schedule. WeeklySchedule + price_account .. Solana Account +``` + +Here is a snapshot of the Japanese Yen product account on Pythnet: + +```sh copy +product_account .. eAnmHaCS2J1XPEb6zohWFrnXD3Mni3wTrfKGhkoQmcZ + asset_type...... FX + base............ USD + description..... US DOLLAR / JAPANESE YEN + generic_symbol.. USDJPY + quote_currency.. JPY + symbol.......... FX.USD/JPY + tenor........... Spot + weekly_schedule. America/New_York,O,O,O,O,00:00-17:00,C,17:00-24:00 + price_account .. H6dt83FavYgfJR8oV7HewKWZjzveFFiDhq41VbmDYnVF +``` + +**Other Fields** + +- `weekly_schedule` - Optional field. When set, contents are used by publishers to learn about a symbol's typical market hours. See [Weekly Schedule Format](schedule-format#weekly-schedule-format-deprecated) for a detailed format specification. + +**Best Practices** + +The users should not rely on the symbol name being unchanging or parse data out of the symbol. + +Instead, programs should always use the different attributes to identify the product you are interested in. You have to ensure that anything which is used to compose the symbol is made available as a stand-alone attribute. + +**Caveats** + +There is a limit of 464 bytes to store the attribute dictionary in v2 (the product account is 512 bytes and 48 are used for other fields). This has to hold all the keys and values, plus field separators. There is no data compression or abbreviation. diff --git a/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/schedule-format.mdx b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/schedule-format.mdx new file mode 100644 index 0000000000..761d1e051e --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/pythnet-reference/schedule-format.mdx @@ -0,0 +1,108 @@ +--- +title: Schedule Format +description: Learn how the Pyth schedule field governs market hours for publishing +slug: /price-feeds/core/pythnet-reference/schedule-format +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +This document describes the format for the `schedule` field in Pyth product metadata. +The `schedule` field defines a product's market hours, including its timezone, weekly schedule, and any holiday exceptions. +It controls the publishing schedule of `pyth-agent`, restricting it to follow a predetermined timetable. +This field is particularly useful for: + +- FX +- Metals +- Stocks + +## Format + +```plain +Timezone;WeeklySchedule;Holidays +``` + +**If `schedule` is omitted for a symbol, pyth-agent will revert to the deprecated [`weekly_schedule`](#weekly-schedule-format-deprecated) field. +If `weekly_schedule` is also undefined, pyth-agent will default to 24/7 publishing, which was the standard behavior prior to this feature.** + +**Detailed Definitions** + +- `Timezone` - A human-readable tz database TZ identifier of the market’s local timezone, such as `America/New_York`. + **Full list of identifiers can be found [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)**. + + Daylight-saving time is automatically handled by the pyth-agent. + +- `WeeklySchedule` - A list of seven comma-separated `DaySchedule` entries that define the recurring weekly schedule of a product’s market hours. + Each `DaySchedule` entry corresponds to a day of the week, starting from Monday. + None of the comma-separated values can be omitted. +- `Holidays` - A list of comma-separated `MonthDay/DaySchedule` entries. + Each entry specifies the schedule for a specific day of the year, overriding the `WeeklySchedule` for that date. + This list can be empty. `MonthDay` is a compact date format where the first two digits represent the month (01 for January, 12 for December), + and the last two digits represent the day of the month (e.g., `0415` for April 15th). **Leading zeros are mandatory**. +- `DaySchedule` - A single day’s schedule. `DaySchedule` can be one of the following: + + - `O` for all-day open + - `C` for all-day closed + - `HourMinute-HourMinute[&HourMinute-HourMinute[&...]]` for specific open and close times in the market-local timezone. + The hour and minute are combined into a single 4-digit number, where the first two digits represent the hour (00 to 24), + and the last two digits represent the minute (00 to 59). + For example, `0415` represents 4:15 AM. The open time must precede the close time, and the range is inclusive. + + - `24` can only be used to specify `2400`, which represents the final moment of a given day. + - Context: Without this special case, the next best thing would be `2359` which could cause a symbol to go down between `2359` and the next day’s `0000` for a full minute. + - **Leading zeros are mandatory**. + + If there are multiple open and close times per day (e.g., maintenance window) you can specify them by using `&` in between. For instance `0000-1200&1300-2400` means that the + market is open all day except between 12:00 and 13:00. + +**Examples** + +- `Europe/Lisbon;O,O,O,O,O,C,C;` - 24h open from Monday to Friday, according to Lisbon’s perspective of midnight. Closed on Saturdays and Sundays. +- `America/New_York;0930-1630,0930-1630,0930-1630,0930-1630,0930-1630,C,C;` - Open 9:30AM - 4:30PM ET (EDT or EST) + from Monday to Friday. Closed outside specified ranges, on Saturdays and on Sundays. Based off real-life NASDAQ hours. +- `Israel;0959-1714,0959-1714,0959-1714,0959-1714,C,C,0959-1539;` - Interesting edge case of the Tel-Aviv Stock Exchange. Open with reduced hours on Sundays, closed on Friday and Saturday. Note the slash-less timezone name. +- `Africa/Johannesburg;C,C,C,C,C,C,C;` - Trivial made-up example. The market is not trading on any day - exact opposite of 24/7 trading. Pyth-agent instances observing this value will not publish the product at any time. Note: The timezone has no effect in this case. +- `Europe/London;O,O,O,O,O,O,O;` - Trivial example. The market is open at all times and the timezone has no effect. Equivalent to default 24/7 behavior when `schedule` and `weekly_schedule` is not specified on a symbol. +- `America/New_York;O,O,O,O,O,C,C;1224/0930-1300,1225/C` - An example of specifying holidays. The market closes early on Christmas Eve and is fully closed on Christmas Day. +- `America/New_York;C,C,C,C,0930-1530&1830-2200,C,C;` - Only open Friday between 9:30AM - 3:30PM and 6:30PM - 10:00PM ET (EDT or EST) + +## Weekly Schedule Format (Deprecated) + + + This field is deprecated in favor of `schedule`. + + +This document outlines the rules for specifying contents of a new Pyth product metadata field - `weekly_schedule` . The field specifies the recurring weekly schedule of a product’s market hours. It serves as a reference for `pyth-agent` to stop publishing outside the hours specified in the schedule. Notable use cases include: + +- FX +- Metals +- Stocks + +## Format + +```plain +Timezone,MHKind,MHKind,MHKind,MHKind,MHKind,MHKind,MHKind +``` + +**Note: None of the comma-separated values can be ommitted - exactly one timezone and seven subsequent per-day schedules are required. That said, ommitting `weekly_schedule` on a symbol is allowed and will cause pyth-agent to default to 24/7 publishing (the usual behavior before this feature)** + +**Detailed Definitions** + +- `Timezone` - A human-readable tz database TZ identifier of the market’s local timezone - e.g. `America/New_York`. **Full list of identifiers can be found [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)**. Notes: + - Daylight-saving time - Handled automatically by pyth-agent code dealing with the format. +- `MHKind` - A single week day’s schedule. The `MHKind` values describe week days from Monday to Sunday, in that order. `MHKind` is defined as one of: + - `O` - all-day open + - `C` - all-day closed + - `Hour:Minute-Hour:Minute` - specific open and close times in the market-local timezone. Open time must come before close time. **The range is inclusive.** Definitions: + - `Hour` - number of hours from `00` to `24` . Notes: + - Leading zeros are optional - e.g. `9` and `09`, `0` and `00` are equivalent. + - `24` can only be used to specify `24:00`. This value is used to express the final moment of a given day (split-second before `00:00` on the next day). Context: Without this special case, the next best thing would be `23:59` which could cause a symbol to go down between `23:59` and the next day’s `00:00` for a full minute. + - `Minute` - number of minutes from `00` to `59`. Notes: + - Leading zeros are **mandatory** - e.g. `9:05`, `9:00`, `15:07` + +**Examples** + +- `Europe/Lisbon,O,O,O,O,O,C,C` - 24h open from Monday to Friday, according to Lisbon’s perspective of midnight. Closed on Saturdays and Sundays. +- `America/New_York,9:30-16:30,9:30-16:30,9:30-16:30,9:30-16:30,9:30-16:30,C,C` - Open 9:30AM - 4:30PM ET (EDT or EST) from Monday to Friday. Closed outside specified ranges, on Saturdays and on Sundays. Based off real-life NASDAQ hours. +- `Israel,9:59-17:14,9:59-17:14,9:59-17:14,9:59-17:14,C,C,9:59-15:39` - Interesting edge case of the Tel-Aviv Stock Exchange. Open with reduced hours on Sundays, closed on Friday and Saturday. Note the slash-less timezone name. +- `Africa/Johannesburg,C,C,C,C,C,C,C` - Trivial made-up example. The market is not trading on any day - exact opposite of 24/7 trading. Pyth-agent instances observing this value will not publish the product at any time. Note: The timezone has no effect in this case. +- `Europe/London,O,O,O,O,O,O,O` - Trivial example. The market is open at all times and the timezone has no effect. Equivalent to default 24/7 behavior when `weekly_schedule` is not specified on a symbol. diff --git a/apps/developer-hub/content/docs/price-feeds/core/rate-limits.mdx b/apps/developer-hub/content/docs/price-feeds/core/rate-limits.mdx new file mode 100644 index 0000000000..db1a484d41 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/rate-limits.mdx @@ -0,0 +1,9 @@ +--- +title: Rate Limits +description: Rate Limits for the Pyth Hermes and Benchmarks APIs +slug: /price-feeds/core/rate-limits +--- + +In order to maximize the reliability of the Pyth Hermes and Benchmarks APIs, a request rate limit is enforced. All endpoints limits are set at **30 requests every 10 seconds per IP address**. + +**One exception**: the TradingView endpoint will allow 90 requests every 10 seconds. Clients issuing request above the limit will receive a 429 (Too Many Requests) response for the subsequent 60-second period. diff --git a/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/index.mdx new file mode 100644 index 0000000000..1355629873 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/index.mdx @@ -0,0 +1,23 @@ +--- +title: Schedule Price Updates +description: Compare options for automating on-chain Pyth price updates +slug: /price-feeds/core/schedule-price-updates +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +This guide introduces the available options for scheduling Pyth price updates at regular intervals. Pyth is a pull oracle, so applications are typically responsible for updating prices on-chain. To learn more about the model, review [What is a Pull Oracle?](/price-feeds/core/pull-updates). + +The Pyth Data Association sponsors regular updates for select feeds. See the [push feeds overview](/price-feeds/core/push-feeds) for the current schedule and use the [request form](https://tally.so/r/nGz2jj) if you need additional coverage. + +You can also automate updates using any of the following services: + +- [Adrastia’s Pyth Price Feed Updater](./using-adrastia) — a managed service for time- and deviation-based updates on any EVM chain +- [Gelato](./using-gelato) — a turnkey automation platform for scheduled updates +- [Price Pusher](./using-price-pusher) — an off-chain service you can operate to trigger updates when specific time or price thresholds are met + + + Lower deviation thresholds lead to more frequent on-chain transactions. While + this improves freshness, it also increases gas costs. Adjust thresholds + according to your product’s latency and cost requirements. + diff --git a/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/meta.json b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/meta.json index c986fe3e59..f3eee44897 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/meta.json @@ -1,7 +1,3 @@ { - "pages": [ - "[Using Adrastia](./using-adrastia)", - "[Using Gelato](./using-gelato)", - "[Using Price Pusher](./using-price-pusher)" - ] + "pages": ["using-price-pusher", "using-adrastia", "using-gelato"] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-adrastia.mdx b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-adrastia.mdx new file mode 100644 index 0000000000..5b4f150b6c --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-adrastia.mdx @@ -0,0 +1,40 @@ +--- +title: Using Adrastia +description: Coordinate managed Pyth price updates with Adrastia’s automation service +slug: /price-feeds/core/schedule-price-updates/using-adrastia +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +[Adrastia](https://adrastia.io) is an automation platform founded by TRILEZ SOFTWARE INC. leveraging more than a decade of operational experience with AI agents to deliver reliable automated systems. The team emphasizes reliability, transparency, and prudence while helping DeFi projects enhance data freshness and resilience. + +## Pyth Price Feed Updater + +Adrastia’s Pyth Price Feed Updater is a managed, white-glove service that pushes price updates as soon as configured trigger conditions are met. Integration is intentionally lightweight—Adrastia operates the infrastructure so teams can keep their focus on product development. + +## Engagement Process + +Adrastia is building a decentralized, permissionless experience for managing automation workloads. Until that interface ships, onboarding follows a simple off-chain workflow: + +1. Contact Adrastia via [support@adrastia.io](mailto:support@adrastia.io) or [Discord](https://discord.adrastia.io/). +2. Share the price feed IDs you want to keep updated on-chain. +3. Review the configuration (public or private) they prepare in GitHub and propose adjustments if needed. +4. Sign the service agreement authorizing Adrastia to run automation on your behalf. +5. Fund the Automatos worker addresses they provide with the gas required for updates. +6. Receive access to the analytics dashboard once the service is live. +7. Request a dedicated status page to monitor execution (optional). +8. Settle the monthly invoice for the service. + +## Configuration Model + +Each price feed can trigger updates when: + +- The price changes by at least a specified threshold, or +- The heartbeat interval elapses, ensuring at least one update within the chosen period + +Feeds can also define **early update** rules. When one feed meets its primary condition, Adrastia can preemptively update related feeds to save gas by batching proofs and transactions. + + + For pricing, analytics, and technical reference material, consult [Adrastia’s + documentation](https://docs.adrastia.io/automatos/pyth-price-feed-updater). + diff --git a/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-gelato.mdx b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-gelato.mdx new file mode 100644 index 0000000000..ca82dd14ad --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-gelato.mdx @@ -0,0 +1,96 @@ +--- +title: Using Gelato +description: Automate Pyth price updates with Gelato Web3 Functions +slug: /price-feeds/core/schedule-price-updates/using-gelato +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Step, Steps } from "fumadocs-ui/components/steps"; + +This guide shows how to schedule Pyth price updates with a Gelato Web3 Function. The task refreshes on-chain prices after a fixed interval or when a configured deviation threshold is exceeded. + +## Introduction to Gelato + +[Gelato](https://www.gelato.network/) is a decentralized backend for EVM chains that lets developers build automated, gasless, and off-chain-aware smart contracts. Web3 Functions (W3F) are decentralized cloud functions that connect contracts to off-chain computation and data sources. + +## Gelato Web3 Function for Pyth + +Gelato hosts a reusable Web3 Function that submits Pyth price updates based on configuration defined in a `config.yaml` file. You edit that configuration through a GitHub gist—Gelato reads it on each run and applies any changes automatically. + +## Setup + + + + TypeScript-based Web3 Functions require whitelisting. Reach out to the Gelato team via + [Discord](https://discord.com/invite/ApbA39BKyJ) to request access before creating your task. + + + 1. Sign in to GitHub and create a gist containing a file named `config.yaml`. + 2. Copy the [sample configuration](https://gist.github.com/swimricky/18b2a5ad9c1a605f1cf5c19ac1d2f1d9) and edit the parameters to match your environment, feeds, update frequency, and deviation thresholds. Additional examples are available in the [pyth-gelato-price-pusher repository](https://github.com/pyth-network/pyth-gelato-price-pusher). + 3. Save the gist. You can update the configuration at any time; the task will pick up changes automatically. + + + Use the prefilled task link to deploy the Web3 Function: + + + https://app.gelato.network/new-task?cid=QmbNPFa3ixUpphUzKJwq3F9bjC9w63FBYQ4iV3s2LpiftN + + + The CID above points to the official Web3 Function hosted on IPFS. You can review the source code in the + [pyth-gelato-price-pusher repo](https://github.com/pyth-network/pyth-gelato-price-pusher/tree/main/web3-functions/pyth-oracle-w3f-priceIds). + + When prompted: + + - Select your target network. + - In **Task Secrets**, set `GIST_ID` to the ID portion of the gist URL you created in the previous step. + - Complete the remaining task settings as needed. + + ![](/images/guides/gelato/task-creation-gist-id.png) + + + + Two fee sources must be funded before execution: + + - **Gelato fees** are paid through [1Balance](https://docs.gelato.network/web3-services/1balance). After whitelisting, deposit USDC on Polygon via the [1Balance dashboard](https://app.gelato.network/1balance). These funds cover compute costs and transaction gas across supported networks. (Testnet runs are subsidized by Gelato.) + - **Pyth fees** are paid in the native token of the chain where updates occur. Gelato deploys a `dedicatedMsgSender` proxy contract for each task creator. Transfer native tokens directly to that address on every chain you operate. You can find the address in the Gelato app under task settings. + + ![](/images/guides/gelato/deposit-usdc.png) + + ![](/images/guides/gelato/dedicated-msg-sender.png) + + + Gelato’s free tier has execution limits. Review current plans at + [app.gelato.network/1balance/subscriptions](https://app.gelato.network/1balance/subscriptions/functions?networkGroup=mainnets&type=monthly) + + + + + Once the task is active, track executions from the Gelato dashboard. The interface lists recent runs, transaction hashes, and any errors. + + ![](/images/guides/gelato/task-execution.png) + + + + +## Managing Your Task + +### Monitoring + +Set up notifications to ensure 1Balance and `dedicatedMsgSender` balances remain funded and executions succeed: + +- [1Balance Alerts](https://docs.gelato.network/web3-services/1balance/1balance-alerts) +- [Balance Alerts](https://docs.gelato.network/web3-services/web3-functions/analytics-and-monitoring) + +Gelato supports alert delivery through Telegram or Discord. + +### Updating Configuration + +To adjust feeds or thresholds, edit the `config.yaml` gist. The task refreshes configuration based on the +`configRefreshRateInSeconds` setting, limiting GitHub requests. To confirm the latest configuration is in use, open the Gelato task details, select **Storage**, and inspect the `pythConfig` entry. + +![](/images/guides/gelato/storage-pyth-config.png) + +## Advanced Usage + +Need deeper customization than the shared Web3 Function supports? Fork the +[pyth-gelato-price-pusher](https://github.com/pyth-network/pyth-gelato-price-pusher) repository, deploy your own Web3 Function, and create a task using its CID. Refer to the project `README.md` and the [Gelato Web3 Functions documentation](https://docs.gelato.network/web3-services/web3-functions) for deployment guidance. diff --git a/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-price-pusher.mdx b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-price-pusher.mdx new file mode 100644 index 0000000000..108a89dd34 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/schedule-price-updates/using-price-pusher.mdx @@ -0,0 +1,14 @@ +--- +title: Using Price Pusher +description: Automate on-chain Pyth price updates with the Price Pusher service +slug: /price-feeds/core/schedule-price-updates/using-price-pusher +--- + +The [Price Pusher](https://github.com/pyth-network/pyth-crosschain/tree/main/apps/price_pusher) +is an off-chain service that continuously pulls price updates onto a blockchain. +Anyone can operate this service to keep on-chain Pyth prices current based on configurable criteria such as minimum update intervals or price change thresholds. + +Running the Price Pusher is a straightforward way to migrate from a push oracle: protocols that depend on regular updates can achieve the same behavior by operating this service. Refer to the project README for setup instructions and configuration details. + +For a walkthrough, see Ali’s tutorial on building with Pyth data: +[How to Build with Pyth Data on EVM Chains (with Pusher): Pyth Tutorials](https://youtu.be/yhmo81JOH10). diff --git a/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/evm.mdx b/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/evm.mdx new file mode 100644 index 0000000000..1a9afd8c85 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/evm.mdx @@ -0,0 +1,39 @@ +--- +title: Troubleshoot EVM Price Feeds Contract +description: Resolve common issues when integrating Pyth price feeds on EVM chains +slug: /price-feeds/core/troubleshoot/evm +--- + +This reference page is designed to help you troubleshoot common issues you may encounter when using Pyth Price Feeds on EVM chains. +Follow the steps provided below to diagnose and resolve the issue. + +#### getPrice() reverts with `StalePrice()` or `0x19abf40e` error + +This error occurs when the requested price feed has not been updated in the last `validTimePeriod`. +The valid time period for the feed can queried using the [`getValidTime()`](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/ethereum/sdk/solidity/AbstractPyth.sol#L22) method. + +To resolve this issue: + +- Update the prices by calling [`updatePriceFeeds()`]("https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/ethereum/sdk/solidity/AbstractPyth.sol#L88") + by passing the latest updateData from [Hermes](https://hermes.pyth.network/docs/#/rest/latest_vaas). +- Another method to fetch the price is [`getPriceUnsafe()`](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/ethereum/sdk/solidity/AbstractPyth.sol#L41) + If the price feed is available, the method will return the latest prices with timestamp of last update. + NOTE: `getPriceUnsafe()` method does not check the freshness of the price. + +#### getPrice() reverts with `PriceFeedNotFound()` or `0x14aebe68` error + +This error occurs when the requested price feed has not been updated on-chain, or the price feed id is incorrect. + +To resolve this issue: + +- Update the prices by calling [`updatePriceFeeds()`](https://api-reference.pyth.network/price-feeds/evm/updatePriceFeeds) + by passing the latest updateData from [Hermes](https://hermes.pyth.network/docs/#/rest/latest_vaas). +- Check the entered [price feed id](../price-feeds.mdx) and [pyth-contract address](https://docs.pyth.network/price-feeds/contract-addresses/evm) to make sure they are correct. + +#### updatePriceFeeds() reverts with `InsufficientFee()` or `0x025dbdd4` error + +This error occurs when the fee provided for updating the price feed is insufficient. +To resolve this issue: + +- Fetch the latest fee by calling [`getUpdateFee()`](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/ethereum/sdk/solidity/IPyth.sol#L112) method and + provide the required fee to `msg.value` when calling [`updatePriceFeeds()`](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/ethereum/sdk/solidity/IPyth.sol#L112) method. diff --git a/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/index.mdx b/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/index.mdx new file mode 100644 index 0000000000..5c3f39ea69 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/index.mdx @@ -0,0 +1,11 @@ +--- +title: Troubleshoot +description: Diagnose common issues affecting Pyth price feeds across supported ecosystems +slug: /price-feeds/core/troubleshoot +--- + +The following guide helps users integrating Pyth price feeds resolve the most common issues they may encounter. +Select the component where you are facing problems to review targeted troubleshooting steps. + +- [EVM Price Feeds Contract](./evm) +- [SVM Price Feeds Contract](./svm) diff --git a/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/meta.json b/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/meta.json index c854a73109..32be387d71 100644 --- a/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/meta.json +++ b/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/meta.json @@ -1,6 +1,3 @@ { - "pages": [ - "[EVM Price Feeds Contract](./evm)", - "[SVM Price Feeds Contract](./svm)" - ] + "pages": ["evm", "svm"] } diff --git a/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/svm.mdx b/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/svm.mdx new file mode 100644 index 0000000000..d2ffc1f021 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/troubleshoot/svm.mdx @@ -0,0 +1,22 @@ +--- +title: Troubleshoot Solana Price Feeds Contract +description: Fix build and runtime issues for Pyth price feeds on Solana and SVM chains +slug: /price-feeds/core/troubleshoot/svm +--- + +This reference page is designed to help you troubleshoot common issues you may encounter when using Pyth Price Feeds on SVM chains. +Follow the steps provided below to diagnose and resolve the issue. + +1. `error[E0277]: the trait bound PriceUpdateV2: anchor_lang::AccountDeserialize is not satisfied{:rust}` + + This error happens when a program using the [`pyth-solana-receiver-sdk`](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/solana/pyth_solana_receiver_sdk) fails to compile. It is caused by an `anchor-lang` version mismatch. + Make sure the transitive version of `anchor-lang` brought by `pyth-solana-receiver-sdk` + matches the version of `anchor-lang` of your program's `Cargo.toml`. + + You can fix it by following these steps: + + - Check the version of `anchor-lang` in your [`Cargo.toml`](https://github.com/guibescos/anchor-pyth/blob/broken-build/programs/anchor-pyth/Cargo.toml) (in the example `0.29.0{:js}`) call it `x.y.z` + - Check the version of `anchor-lang` in the `pyth-solana-receiver-sdk` tree in [`Cargo.lock`](https://github.com/guibescos/anchor-pyth/blob/broken-build/Cargo.lock#L1400) (in the example `0.30.1{:js}`) call it `a.b.c` + - Run `cargo update -p anchor-lang@a.b.c --precise x.y.z{:bash}` + replacing `a.b.c` and `x.y.z` by the versions in the previous steps. For example:\ + `cargo update -p anchor-lang@0.30.1 --precise 0.29.0{:bash}` diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-historic-price-data.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-historic-price-data.mdx new file mode 100644 index 0000000000..57de9c894a --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-historic-price-data.mdx @@ -0,0 +1,109 @@ +--- +title: Use Historic Price Data (Benchmarks) +description: Learn how to query and verify historical Pyth price feeds +slug: /price-feeds/core/use-historic-price-data +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Step, Steps } from "fumadocs-ui/components/steps"; + +This guide explains how to integrate **Pyth Benchmarks** to access historical price data across applications. The Benchmarks API is available on all Pythnet chains. + + + Throughout this guide, **Benchmarks** refers to Pyth’s historical price data + service. + + +## Overview + +Pyth Benchmarks lets you query historical prices at specific timestamps. Typical use cases include: + +- **Contract settlement** for derivatives such as options or futures +- **Backtesting** trading strategies with historical data +- **Audit and compliance** workflows that require price verification +- **Analytics** to analyze market behavior over time + +Benchmarks supports two complementary flows: + + + + Retrieve data from the [Benchmarks API](https://benchmarks.pyth.network/docs#/Updates/price_updates_timestamp_route_v1_updates_price__timestamp__get) or through the + [Hermes timestamp API](https://hermes.pyth.network/docs/#/rest/timestamp_price_updates). + Two REST endpoints are available: + + - [`/v1/updates/price/{timestamp}`](https://benchmarks.pyth.network/docs#/): returns prices for the requested feeds at a given timestamp. + - [`/v1/updates/price/{timestamp}/{interval}`](https://benchmarks.pyth.network/docs#/): returns prices for a feed at the given timestamp and interval. + + + The interval parameter represents the number of seconds added to the provided timestamp. + For example, with timestamp `1716400000` and interval `60`, the API returns price updates + from `1716400000` through `1716400060` (inclusive). The interval must not exceed `60` + seconds. + + + + + After fetching price updates, pass the result to [`parsePriceFeedUpdates`](https://api-reference.pyth.network/price-feeds/evm/parsePriceFeedUpdates) instead of [`updatePriceFeeds`](https://api-reference.pyth.network/price-feeds/evm/updatePriceFeeds) when interacting with the Pyth contract. + +```solidity copy +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; +import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; + +contract HistoricalPriceConsumer { + IPyth public pyth; + + constructor(address _pyth) { + pyth = IPyth(_pyth); + } + + function settleWithHistoricalPrice( + bytes[] calldata priceUpdate, + uint256 priceId, + uint256 minPublishTime, + uint256 maxPublishTime, + ) external { + // The parsePriceFeedUpdates function requires a fee to be paid. + // The fee is the same as the fee for the updatePriceFeeds function. + uint fee = pyth.getUpdateFee(priceUpdate); + PythStructs.Price memory price = pyth.parsePriceFeedUpdates{value: fee}( + priceUpdate, + priceId, + minPublishTime, + maxPublishTime, + ); + + // Use the historical price for settlement + uint256 settlementPrice = uint256(price.price); + // ... settlement logic + } +} +``` + + The verification flow differs from [real-time price updates](/price-feeds/core/use-real-time-data/pull-integration/evm) in that it: + + - Calls `parsePriceFeedUpdates` instead of `updatePriceFeeds` + - Provides the price feed ID to ensure the update matches the feed + - Supplies `minPublishTime` and `maxPublishTime` to enforce the allowable timestamp window, reverting with `PriceFeedNotFoundWithinRange` when updates fall outside the range + + Consult the [API reference](https://api-reference.pyth.network/price-feeds/evm/parsePriceFeedUpdates) for additional implementation details. + + + + +## Additional Resources + +### API Reference + +- [Benchmarks API documentation](https://benchmarks.pyth.network/docs) +- [Pyth on-chain API reference](https://api-reference.pyth.network/price-feeds/evm/parsePriceFeedUpdates) + +### TradingView Integration + +- [TradingView integration](./create-tradingview-charts) for visualization + +### Rate Limits + +- Benchmarks API inherits the same limits as the [Hermes API](./rate-limits) diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-pyth-for-morpho.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-pyth-for-morpho.mdx new file mode 100644 index 0000000000..8b0fb13983 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-pyth-for-morpho.mdx @@ -0,0 +1,69 @@ +--- +title: Use Pyth for Morpho Markets +description: Learn how to use Pyth for Morpho Markets +slug: /price-feeds/core/use-pyth-for-morpho +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Step, Steps } from "fumadocs-ui/components/steps"; + +This guide will show how you can leverage Pyth real-time price data to power Morpho markets. + +Pyth provides a wrapper which implements Morpho's `IOracle` interface called [`pyth-morpho-wrapper`](https://github.com/pyth-network/pyth-morpho-wrapper). + +There are two steps to use Pyth price feeds for Morpho markets: + +1. Schedule Price Updates. +2. Deploy the [`MorphoPythOracle.sol`](https://github.com/pyth-network/pyth-morpho-wrapper/blob/main/src/morpho-pyth/MorphoPythOracle.sol) contract for the respective price feed pair. + + + +### Schedule Price Updates + +As a pull oracle, Pyth's users are typically responsible for updating the state of on-chain feeds. +Please see [What is a Pull Oracle?](/price-feeds/core/pull-updates) to learn more about pull updates. + +Consult [Schedule Price Updates](/price-feeds/core/schedule-price-updates) guide for more information. + +The Pyth Data Association sponsors regular on-chain updates for some price feeds. +See [Push Feeds](./push-feeds.mdx) for the current list of feeds and their update parameters. + +If you don't find relevant price IDs in the [Push Feeds](./push-feeds.mdx) list, please contact the Pyth team [here](https://tally.so/r/nGz2jj) to run the Price Pusher for the price feed you need. + + + +### Deploy the Morpho oracle contract + +After running the [Price Pusher](https://github.com/pyth-network/pyth-crosschain/tree/main/apps/price_pusher), you can deploy the Morpho oracle contract using the MorphoPythOracle.sol contract. + +To deploy a MorphoPythOracle on an EVM chain, we highly recommend using the factory MorphoPythOracleFactory. Please refer to the factory addresses [here](https://github.com/pyth-network/pyth-morpho-wrapper?tab=readme-ov-file#factory-addresses). + +If you don't see the factory address for your chain, you can deploy your own factory by using the [`scripts/MorphoPythOracleFactoryDeploy.s.sol`](https://github.com/pyth-network/pyth-morpho-wrapper/blob/main/scripts/MorphoPythOracleFactoryDeploy.s.sol) script or by creating an issue on [this repository](https://github.com/pyth-network/pyth-morpho-wrapper). +If you are deploying, please make sure to update the README.md file with the new factory address. + +To do so, run the [`MorphoPythOracleDeploy.s.sol`](https://github.com/pyth-network/pyth-morpho-wrapper/blob/main/scripts/MorphoPythOracleDeploy.s.sol) script with the following environment variables set: + +- `PYTH_ADDRESS`: The Pyth contract address. This is the address of the Pyth contract deployed on the chain. You can find the address of the Pyth contract for each chain [here](./contract-addresses/evm.md). +- `BASE_VAULT`: The ERC4626 token vault for the base asset. +- `BASE_VAULT_CONVERSION_SAMPLE`: A sample amount for converting base vault units. +- `BASE_FEED1`, `BASE_FEED2`: Pyth price feed ids for the base asset. You can find the price feed ids for each asset in our [price feeds directory](./price-feeds.mdx). +- `BASE_TOKEN_DECIMALS`: Decimal precision of the base asset. +- `QUOTE_VAULT`: The ERC4626 token vault for the quote asset. +- `QUOTE_VAULT_CONVERSION_SAMPLE`: A sample amount for converting quote vault units. +- `QUOTE_FEED1`, `QUOTE_FEED2`: Pyth price feed ids for the quote asset. You can find the price feed ids for each asset in our [price feeds directory](./price-feeds.mdx). +- `QUOTE_TOKEN_DECIMALS`: Decimal precision of the quote asset. +- `PRICE_FEED_MAX_AGE`: The maximum age of the price feed in seconds. Note: This adds an extra safety net to avoid using stale prices. +- `SALT`: A unique identifier to create deterministic addresses for deployed oracles. + +Check more information about these immutable parameters [here](https://docs.morpho.org/getting-started/resources/contracts/oracles/#immutables) and some assumptions to take into account [here](https://docs.morpho.org/getting-started/resources/contracts/oracles/#assumptions). + + + If there is an ERC4626-compliant vault for `BASE_VAULT` or `QUOTE_VAULT`, the + `BASE_TOKEN_DECIMALS` or `QUOTE_TOKEN_DECIMALS` are still the decimals of the + underlying asset of the vault, and not the decimals of the Vault itself. E.g: + for a MetaMorpho WETH vault, as `BASE_VAULT`, the `BASE_TOKEN_DECIMALS` is 18 + as WETH has 18 decimals. + + + + diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/fuel.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/fuel.mdx new file mode 100644 index 0000000000..65c8a9e8ae --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/fuel.mdx @@ -0,0 +1,191 @@ +--- +title: How to Use Real-Time Data in Fuel Contracts +description: Consume Pyth Network prices in Fuel applications +slug: /price-feeds/core/use-real-time-data/pull-integration/fuel +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Tab, Tabs } from "fumadocs-ui/components/tabs"; + +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: + + + + ```bash copy npm install --save @pythnetwork/pyth-fuel-js ``` + + ```bash copy yarn add @pythnetwork/pyth-fuel-js ``` + + +## Write Contract Code + +The code snippet below provides an example module fetching the ETH/USD price from Pyth price feeds: + +```rust 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) -> u64; + #[payable] + fn update_price_feeds(update_fee: u64, update_data: Vec); +} + +const PYTH_MAINNET_CONTRACT_ID = 0x1c86fdd9e0e7bc0d2ae1bf6817ef4834ffa7247655701ee1b031b52a24c523da; // Mainnet Contract +const PYTH_TESTNET_CONTRACT_ID = 0x25146735b29d4216639f7f8b1d7b921ff87a1d3051de62d6cceaacabeb33b8e7; // Testnet Contract +const FUEL_ETH_BASE_ASSET_ID = 0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07; + +impl UpdatePrice for Contract { + fn valid_time_period() -> u64 { + let pyth_contract = abi(PythCore, PYTH_MAINNET_CONTRACT_ID); + let period = pyth_contract.valid_time_period(); + period + } + fn get_price(price_feed_id: PriceFeedId) -> Price { + let pyth_contract = abi(PythCore, PYTH_MAINNET_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_MAINNET_CONTRACT_ID); + let price = pyth_contract.price_unsafe(price_feed_id); + price + } + fn update_fee(update_data: Vec) -> u64 { + let pyth_contract = abi(PythCore, PYTH_MAINNET_CONTRACT_ID); + let fee = pyth_contract.update_fee(update_data); + fee + } + #[payable] + fn update_price_feeds(update_fee: u64, update_data: Vec) { + let pyth_contract = abi(PythCore, PYTH_MAINNET_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`. + + + 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). + + +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_MAINNET_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(ETH_USD_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. diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/iota.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/iota.mdx new file mode 100644 index 0000000000..d8a97dd771 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/iota.mdx @@ -0,0 +1,208 @@ +--- +title: How to Use Real-Time Data in IOTA Contracts +description: Consume Pyth Network prices in IOTA applications +slug: /price-feeds/core/use-real-time-data/pull-integration/iota +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Tab, Tabs } from "fumadocs-ui/components/tabs"; + +This guide explains how to use real-time Pyth data in IOTA applications. + +## Install Pyth SDK + +Use the following dependency in your `Move.toml` file to use the latest Pyth IOTA package and its dependencies: + + + +```bash copy +[dependencies.Pyth] +git = "https://github.com/pyth-network/pyth-crosschain.git" +subdir = "target_chains/sui/contracts" +rev = "iota-contract-testnet" + +[dependencies.Wormhole] +git = "https://github.com/pyth-network/pyth-crosschain.git" +subdir = "target_chains/sui/contracts/vendor/wormhole_iota_testnet/wormhole" +rev = "iota-contract-testnet" + +[dependencies.Iota] +git = "https://github.com/iotaledger/iota.git" +subdir = "crates/iota-framework/packages/iota-framework" +rev = "751c23caf24efd071463b9ffd07eabcb15f44f31" + +```` + + +```bash copy +[dependencies.Pyth] +git = "https://github.com/pyth-network/pyth-crosschain.git" +subdir = "target_chains/sui/contracts" +rev = "iota-contract-mainnet" + +[dependencies.Wormhole] +git = "https://github.com/pyth-network/pyth-crosschain.git" +subdir = "target_chains/sui/contracts/vendor/wormhole_iota_mainnet/wormhole" +rev = "iota-contract-mainnet" + +[dependencies.Iota] +git = "https://github.com/iotaledger/iota.git" +subdir = "crates/iota-framework/packages/iota-framework" +rev = "751c23caf24efd071463b9ffd07eabcb15f44f31" +```` + + + + +Pyth also provides a javascript SDK to construct transaction blocks that update price feeds: + + + +```bash +# NPM +npm install --save @pythnetwork/pyth-iota-js + +# Yarn + +yarn add @pythnetwork/pyth-iota-js + +```` + + + +## Write Contract Code + +The code snippet below provides a general template for what your contract code should look like: + +```rust {18} copy +module pyth_example::main { + use iota::clock::Clock; + use pyth::price_info; + use pyth::price_identifier; + use pyth::price; + use pyth::pyth; + use pyth::price_info::PriceInfoObject; + + const E_INVALID_ID: u64 = 1; + + public fun use_pyth_price( + // Other arguments + clock: &Clock, + price_info_object: &PriceInfoObject, + ){ + let max_age = 60; + // Make sure the price is not older than max_age seconds + let price_struct = pyth::get_price_no_older_than(price_info_object,clock, max_age); + + // Check the price feed ID + let price_info = price_info::get_price_info_from_price_info_object(price_info_object); + let price_id = price_identifier::get_bytes(&price_info::get_price_identifier(&price_info)); + + // ETH/USD price feed ID + // The complete list of feed IDs is available at https://docs.pyth.network/price-feeds/price-feeds + // Note: IOTA uses the Pyth price feed ID without the `0x` prefix. + assert!(price_id!=x"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", E_INVALID_ID); + + // Extract the price, decimal, and timestamp from the price struct and use them + let decimal_i64 = price::get_expo(&price_struct); + let price_i64 = price::get_price(&price_struct); + let timestamp_sec = price::get_timestamp(&price_struct); + } +} +```` + +One can consume the price by calling `pyth::get_price` abovementioned or other utility functions on the `PriceInfoObject` in the Move module + +The code snippet below provides an example of how to update the Pyth price feeds: + +```ts copy +import { IotaPriceServiceConnection, IotaPythClient } from "@pythnetwork/pyth-iota-js"; +import { Transaction } from "@iota/iota-sdk/transactions"; + +// Get the Stable Hermes service URL from https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes +const connection = new IotaPriceServiceConnection("https://hermes-beta.pyth.network"); + +const priceIDs = [ + // You can find the IDs of prices at https://docs.pyth.network/price-feeds/price-feeds + "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", // BTC/USD price ID + "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", // ETH/USD price ID +]; + +const priceUpdateData = await connection.getPriceFeedsUpdateData(priceIDs); + +// It is either injected from the browser (https://www.npmjs.com/package/@iota/dapp-kit) +// or instantiated in the backend via some private key (https://www.npmjs.com/package/@iota/iota-sdk) +const wallet: SignerWithProvider = getWallet(); +// Get the state IDs of the Pyth and Wormhole contracts from +// https://docs.pyth.network/price-feeds/contract-addresses/iota +const wormholeStateId = "0x8bc490f69520a97ca1b3de864c96aa2265a0cf5d90f5f3f016b2eddf0cf2af2b"; +const pythStateId = "0x68dda579251917b3db28e35c4df495c6e664ccc085ede867a9b773c8ebedc2c1"; + +const client = new IotaPythClient(wallet.provider, pythStateId, wormholeStateId); +const tx = new Transaction(); +const priceInfoObjectIds = await client.updatePriceFeeds(tx, priceUpdateData, priceIDs); + +tx.moveCall({ + target: `pyth_example::main::use_pyth_price`, + arguments: [ + ..., // other arguments needed for your contract + tx.object(priceInfoObjectIds[0]), + ], +}); + +const txBlock = { + transaction: tx, + wallet, + options: { + showEffects: true, + showEvents: true, + }, +}; + +const result = await wallet.signAndExecuteTransaction(txBlock); +``` + +By calling the `updatePriceFeeds` function, the `IotaPythClient` adds the necessary transactions to the transaction block to update the price feeds. + + + +Your IOTA Move module **should NOT** have a hard-coded call to `pyth::update_single_price_feed.` In other words, a contract should **never call** the IOTA Pyth `pyth::update_single_price_feed` entry point. Instead, it should be called directly from client code (e.g., Typescript or Rust). + +When IOTA contracts are [upgraded](https://docs.iota.org/developer/iota-101/move-overview/package-upgrades/introduction), the address changes, which makes the old address no longer valid. If your module has a hard-coded call to `pyth::update_single_price_feed` living at a fixed call-site, it may eventually get bricked due to how Pyth upgrades are implemented. (Pyth only allow users to interact with the most recent package version for security reasons). + +Therefore, you should build a [IOTA programmable transaction](https://docs.iota.org/developer/iota-101/transactions/ptb/programmable-transaction-blocks-overview) that first updates the price by calling `pyth::update_single_price_feed` at the latest call-site from the client-side and then call a function in your contract that invokes `pyth::get_price` on the `PriceInfoObject` to get the recently updated price. +You can use `IOTAPythClient` to build such transactions and handle all the complexity of updating the price feeds. + +Consult [Fetch Price Updates](/price-feeds/core/fetch-price-updates) for more information on how to fetch the `pyth_price_update`. + + + +## Additional Resources + +You may find these additional resources helpful for developing your IOTA application. + +### CLI Example + +[This example](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/iota/cli) shows how to update prices on a IOTA network. It does the following: + +1. Fetches update data from Hermes for the given price feeds. +1. Call the Pyth IOTA contract with a price update. + +You can run this example with `npm run example-relay`. A full command that updates prices on the IOTA testnet looks like this: + +```bash +export IOTA_KEY=YOUR_PRIV_KEY; +npm run example-relay -- --feed-id "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace" \ +--hermes "https://hermes.pyth.network" \ +--full-node "https://api.testnet.iota.cafe" \ +--pyth-state-id "0x68dda579251917b3db28e35c4df495c6e664ccc085ede867a9b773c8ebedc2c1" \ +--wormhole-state-id "0x8bc490f69520a97ca1b3de864c96aa2265a0cf5d90f5f3f016b2eddf0cf2af2b" +``` + +### Contract Addresses + +Consult [IOTA Contract Addresses](../../contract-addresses/iota) to find the package IDs. + +### Pyth Price Feed IDs + +Consult [Pyth Price Feed IDs](/price-feeds/core/price-feeds) to find Pyth price feed IDs for various assets. diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/near.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/near.mdx new file mode 100644 index 0000000000..03f625b84b --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/near.mdx @@ -0,0 +1,347 @@ +--- +title: How to Use Real-Time Data in Near Contracts +description: Consume Pyth Network prices in Near applications +slug: /price-feeds/core/use-real-time-data/pull-integration/near +--- + +## Pyth on NEAR + +Pyth price feeds on NEAR are managed through the main NEAR Pyth smart +contract, enabling seamless interaction with on-chain data. In NEAR, +these interactions are facilitated by specific functions within the +Pyth receiver contract. This contract acts as an interface to Pyth +price feeds, handling the retrieval and updating of price data. + +The two Key functions in the Pyth receiver contract to get started +are as follows: + +1. [`update_price_feeds`](#update_price_feeds) + _(updates Pyth smart contract with the price feed you provide)_ + + - args: `data` + - type: `object` + - example: `{ "data": "504e41...' }` + +2. [`get_price`](#get_price) (fetches the most recent price stored in the contract)\_ + - args: `price_identifier` + - type: `object` + - example: `{ price_identifier: 'f9c0172ba10dfa8...' }` + +These functions are core for interacting with Pyth price feeds in +NEAR-based applications, providing a reliable and up-to-date source of +price information. + +For a full overview of methods provided by the NEAR +contract, see [the interface](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/near/receiver/src/ext.rs) exposed by the receiver contract. + +## Getting Started + +To get started with Pyth oracle you will need to gather the following information which differ between networks: + +- Price ID(s) +- HermesAPI Endpoint +- Smart contract address + +| Network | Price Feed IDs | Hermes API Address | Contract Address | +| --------- | -------------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------- | +| `testnet` | [NEAR `testnet` Price Feed IDs](/price-feeds/core/price-feeds) | `hermes-beta.pyth.network` | [pyth-oracle.testnet](https://testnet.nearblocks.io/address/pyth-oracle.testnet) | +| `mainnet` | [NEAR `mainnet` Price Feed IDs](/price-feeds/core/price-feeds) | `hermes.pyth.network` | [pyth-oracle.near](https://nearblocks.io/address/pyth-oracle.near) | + +Note: When using Price Feed IDs, you will need to remove the `0x` prefix. + +--- + +### `update_price_feeds` + +> Updates the Pyth Oracle contract data with the price feed you provide. + +- args: `data` _(off-chain hex-encoded price feed)_ +- type: `object` +- example: `{ "data": "504e41...' }` + +Update the Pyth Oracle contract with new price feed data in two main steps: + +1. [Fetch off-chain price feed](#1-fetch-off-chain-price-feed) +2. [Update Pyth Oracle contract with off-chain price feed](#2-update-pyth-oracle-contract-price-feed) + +#### 1) Fetch off-chain price feed + +You can obtain an off-chain price feed using Pyth's [Hermes API](https://hermes-beta.pyth.network/docs/). + +To use these endpoints, you will need to provide a Price Feed ID and ensure you are targeting the correct network. See [Getting Started](#getting-started) for more information. + +Here is a node.js example of fetching the latest price feed using `/v2/updates/price/latest` endpoint: + +`Example:` + +```js +const axios = require("axios"); + +// There are separate endpoints for testnet and mainnet +const HERMES_TESTNET_URL = "https://hermes-beta.pyth.network"; +const HERMES_MAINNET_URL = "https://hermes.pyth.network"; + +async function getHermesPriceData(priceId, network) { + try { + let url; + network === "testnet" + ? (url = HERMES_TESTNET_URL) + : (url = HERMES_MAINNET_URL); + + // Fetch the price data from the Hermes API + const response = await axios.get( + `${url}/v2/updates/price/latest?ids[]=${priceId}`, + ); + + return response.data.binary.data[0]; + } catch (error) { + console.error( + "Error:", + error.response ? error.response.data : error.message, + ); + } +} + +module.exports = { getHermesPriceData }; +``` + +

+ + See full example on GitHub + +

+ +--- + +### 2) Update Pyth Oracle Contract Price Feed + +After [fetching an off-chain price feed](#1-fetch-off-chain-price-feed), you can now perform a contract call to the Pyth Oracle contract to update. +Call `update_price_feeds` on the Pyth Oracle contract deployed on NEAR with `data` as your arguments. + +`example args:` + +```json +{ + "data": "504e41550100000000a00100000000010070b0ee3a00d1a3c07ee440887eb34a5a35860e6f4b9230fd62f0593fe35c8a3561735a6a37d269c5f166b84ead8918f710dc1be2ee6b51db5b22340ea2c173fc01673d544b00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa7100000000061bc18c014155575600000000000ab0f04600002710f41bc8c224ed983c68dbf5dab7dd34c9129fecfa03005500ca80ba6dc32e08d06f1aa886011eed1d77c77be9eb761cc10d72b7d0a2fd57a600000047e2eb4ef0000000000692480ffffffff800000000673d544b00000000673d544b00000048200e66a00000000005e495a60bb9370c458dd50558b34699b5b179f45e56be22f0a1a0feb1db8469adc8c5efeb53988495bac07bf9efed07f5eee43818150c55055882f6872a228e8e9bc78459ed3ea7fe0b86f3048f6bf0aad34befc46063ab7d200beb8bc9fe5839844d2233546f0742bb665f1e610370fcf8ce5be83d0f47e584b685af87cf3ebcb79e714827dcb99dba579e1a03785052ab3c7c7147d3f7bba822b04dbda159670e9a8d29e7ccf68474b2ca85e00224d29bf65b06b09f95e91703313e053b697b48ac1e4d1c57605a71ab77e7ef276bfe8a369c268333b9a37461bf2b7cb7fd4c005500ecf553770d9b10965f8fb64771e93f5690a182edc32be4a3236e0caaa6e0581a0000000e2ba8cd280000000001b40517fffffff800000000673d544b00000000673d544b0000000e3ea44c6800000000016aee120b47b853f55949284cb8ba0b63824ff9b48cd1da8417f45421b79ee3195fc8d107540a0bbb95c2445b66065754f135cb842db09a7e7ab33f79c546a48db872bd7197b04e3d7b52fbb55b3b9f51707c5a55fac3707cb563dbcde4aadeecc3649c237454cecf519dc567c0da03d81808523aa4fa71815eab25ce7da61b48647bac645d403208135002aab5fde2d7ab3c7c7147d3f7bba822b04dbda159670e9a8d29e7ccf68474b2ca85e00224d29bf65b06b09f95e91703313e053b697b48ac1e4d1c57605a71ab77e7ef276bfe8a369c268333b9a37461bf2b7cb7fd4c" +} +``` + +To perform this contract call you must first create a NEAR account which can be done using `near-cli`. + +Fist, install `near-cli`: + +```bash + +npm install -g near-cli-rs@latest + +``` + +This CLI allows you to simply run `near` and let the prompts guide you through the process. + +To quickly create a NEAR account, run the following command (replacing `your-new-account.testnet` with your desired account name): + +```bash +near account \ +create-account sponsor-by-faucet-service \ +your-new-account.testnet \ +autogenerate-new-keypair save-to-legacy-keychain \ +network-config testnet \ +create +``` + +To perform a contract call to the Pyth Oracle contract, run the following command: + +Replace: + +- `your-account.testnet` with your account name +- `'{"data": "504e41550100..."}'` with your off-chain price feed + +``` +near contract \ + call-function \ + as-transaction pyth-oracle.testnet update_price_feeds \ + json-args '{"data": "504e41550100..."}' \ + prepaid-gas '300.0 Tgas' \ + attached-deposit '0.01 NEAR' \ + sign-as your-account.testnet \ + network-config testnet \ + sign-with-legacy-keychain \ + send +``` + +**Try it out on [Lantstool](https://app.lantstool.dev/import/gh/lantstool/examples.near-protocol/main/integrations/pyth/real-time-price-data/update-price-feed.json)** + +Alternatively, you can use `near-js` libraries to perform the contract call. For this example we will create a simple node.js project. + +First, install the `near-js` libraries we will use: + +```bash +npm install @near-js/client @near-js/keystores-node +``` + +To setup a NEAR connection, we'll create a `connect.js` file that will initialize an RPC provider and signer. This will look for your NEAR credentials in your `.near-credentials` directory. + +```js +// node.js imports +const { join } = require("node:path"); +const { homedir } = require("node:os"); + +// near-js imports +const { + getTestnetRpcProvider, + getSignerFromKeystore, +} = require("@near-js/client"); +const { UnencryptedFileSystemKeyStore } = require("@near-js/keystores-node"); + +// initialize RPC provider and signer +const nearConnect = (sender, network) => ({ + rpcProvider: getTestnetRpcProvider(), + signer: getSignerFromKeystore( + sender, + network, + new UnencryptedFileSystemKeyStore(join(homedir(), ".near-credentials")), + ), +}); + +module.exports = { nearConnect }; +``` + +Next we can create a `update-oracle.js` file that will perform the contract call to update the Pyth Oracle contract's price feed. + +```js +// near-js imports +// https://www.npmjs.com/package/@near-js/client +const { nearConnect } = require("../utils/connect"); +const { functionCall } = require("@near-js/client"); + +const sender = "your-account.testnet"; +const receiver = "pyth-oracle.testnet"; +const network = "testnet"; + +const PRICE_IDS = [ + // Price ids can be found at https://docs.pyth.network/price-feeds/price-feeds + // NOTE: Ensure you are using NEAR specific price ids & remove the '0x' prefix before using them + "f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b", // BTC/USD price id + "ca80ba6dc32e08d06f1aa886011eed1d77c77be9eb761cc10d72b7d0a2fd57a6", // ETH/USD price id +]; + +async function updatePythContractPriceFeeds(network) { + // Connect to the NEAR network + const { rpcProvider, signer } = nearConnect(sender, network); + + // Update the Pyth Oracle contract with the price data + // Performs a NEAR function call to the Pyth Oracle contract + // Deposit for transaction fee (balance will be refunded) + const result = await functionCall({ + sender, + receiver, + method: "update_price_feeds", + args: { data: "504e4155010..." }, + deposit: 10000000000000000000000, + deps: { rpcProvider, signer }, + }); + + console.log( + `Transaction 👉 https://testnet.nearblocks.io/txns/${result.outcome.transaction.hash}`, + ); + return result; +} + +updatePythOracle(); +``` + +

+ + See full example on GitHub + +

+ +Although unused deposit will be refunded, you can calculate an estimate by calling the `get_update_fee_estimate` method against the Pyth contract. + +--- + +### `get_price` + +> Fetches the most recent price feed stored in the Pyth Oracle contract. Is a view method, so does not require a signature or payment. + +- args: `price_identifier` _(unique [price feed identifier](#environment-variables))_ +- type: `object` +- example: `{ price_identifier: 'f9c0172ba10dfa8...' }` + +After [updating the price feed](#update_price_feeds), you can view the feed on-chain by calling `get_price` on the Pyth Oracle contract. Note that this is a view method and does not require a signature or deposit. + +#### NEAR CLI example + +```bash +near contract \ + call-function \ + as-read-only pyth-oracle.testnet get_price \ + json-args '{"price_identifier": "f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b"}' \ + network-config testnet \ + now + +``` + +**Try it out on [Lantstool](https://app.lantstool.dev/import/gh/lantstool/examples.near-protocol/main/integrations/pyth/real-time-price-data/get-price.json)** + +#### NEAR-JS Example + +For this example we will create a simple node.js project. First, install the [`near-js\client`](https://www.npmjs.com/package/@near-js/client) library: + +```bash +npm install @near-js/client +``` + +Create a `get-price.js` file that will perform the view call from the Pyth Oracle contract. Note that this does not require a signature or deposit. + +```js +// near-js import +// https://www.npmjs.com/package/@near-js/client +const { getTestnetRpcProvider, view } = require("@near-js/client"); + +const PRICE_IDS = [ + // Price ids can be found at https://docs.pyth.network/price-feeds/price-feeds + // NOTE: Ensure you are using NEAR specific price ids & remove the '0x' prefix before using them + "f9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b", // BTC/USD price id + "ca80ba6dc32e08d06f1aa886011eed1d77c77be9eb761cc10d72b7d0a2fd57a6", // ETH/USD price id +]; + +async function getPrice(price_ID, symbol) { + try { + const rpcProvider = getTestnetRpcProvider(); + const result = await view({ + account: "pyth-oracle.testnet", + method: "get_price", + args: { price_identifier: price_ID }, + deps: { rpcProvider }, + }); + console.log(symbol, result); + } catch (error) { + console.error(`Error fetching ${symbol} price:`, error.message); + } +} + +getPrice(PRICE_IDS[0], "BTC/USD:"); +``` + +

+ + See full example on GitHub + +

+ +--- + +## On-Chain Prices + +For on-chain price interactions, see the [example contract][] in the +Pyth Github repo for an example of how to update and use prices +within a NEAR contract. + +[example contract]: https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/near/example + +A CLI-based approach can also be taken for interacting with Pyth prices, +see the [update.sh][] example script in the repository to see how to +pull prices with the official NEAR cli. + +[update.sh]: https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/near/scripts/update.sh diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/solana.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/solana.mdx new file mode 100644 index 0000000000..c28aefd1e5 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/solana.mdx @@ -0,0 +1,377 @@ +--- +title: How to Use Real-Time Data in Solana Programs +description: Consume Pyth Network prices in Solana applications +slug: /price-feeds/core/use-real-time-data/pull-integration/solana +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +This guide explains how to use real-time Pyth data in Solana applications. + +## Install Pyth SDKs + +Pyth provides two SDKs for Solana applications to cover the on- and off-chain portions of the integration: + +### Rust SDK + +The [pyth-solana-receiver-sdk](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/solana/pyth_solana_receiver_sdk) crate can be used to consume Pyth prices inside Solana programs written in Rust. +Add this crate to the dependencies section of your `Cargo.toml` file: + +```toml copy +[dependencies] +pyth-solana-receiver-sdk ="x.y.z" # get the latest version from https://crates.io/crates/pyth-solana-receiver-sdk +``` + + + At the time of writing, [pyth-solana-receiver-sdk](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/solana/pyth_solana_receiver_sdk) is compatible with Anchor `v0.28.0{:js}`, `v0.29.0{:js}`, `v0.30.1{:js}` and `v0.31.1{:js}`. + If you are on any other version, please move to `v0.31.1{:js}`. This [repository](https://github.com/guibescos/anchor-pyth/tree/main/programs/anchor-pyth) has a branch for each of these versions containing a minimal working Solana program. + + +### Typescript SDK + +Pyth provides two Typescript packages, [@pythnetwork/hermes-client](https://github.com/pyth-network/pyth-crosschain/tree/main/apps/hermes/client/js) and [@pythnetwork/pyth-solana-receiver](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/solana/sdk/js/pyth_solana_receiver), for fetching Pyth prices and submitting them to the blockchain respectively. +Add these packages to your off-chain dependencies: + +```bash copy +npm install --save @pythnetwork/hermes-client @pythnetwork/pyth-solana-receiver +``` + +## Write Contract Code + +Add the following code to your Solana program to read Pyth prices. +Pyth prices are posted to price update accounts that can be passed to any instruction that needs price data. +For developers using Anchor, simply add an `Account<'info, PriceUpdateV2>` field to the `Context` struct: + +```rust copy +use pyth_solana_receiver_sdk::price_update::{PriceUpdateV2}; + +#[derive(Accounts)] +#[instruction()] +pub struct Sample<'info> { + #[account(mut)] + pub payer: Signer<'info>, + // Add this account to any instruction Context that needs price data. + pub price_update: Account<'info, PriceUpdateV2>, +} +``` + + + Users must ensure that the account passed to their instruction is owned by the Pyth Pull Oracle program. + Using Anchor with the `Account<'info, PriceUpdateV2>` type will automatically perform this check. + However, it is the developer's responsibility to perform this check if they are not using Anchor. + + +Next, update the instruction logic to read the price from the price update account: + +```rust copy +pub fn sample(ctx: Context) -> Result<()> { + let price_update = &mut ctx.accounts.price_update; + // get_price_no_older_than will fail if the price update is more than 30 seconds old + let maximum_age: u64 = 30; + // get_price_no_older_than will fail if the price update is for a different price feed. + // This string is the id of the BTC/USD feed. See https://docs.pyth.network/price-feeds/price-feeds for all available IDs. + let feed_id: [u8; 32] = get_feed_id_from_hex("0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43")?; + let price = price_update.get_price_no_older_than(&Clock::get()?, maximum_age, &feed_id)?; + // Sample output: + // The price is (7160106530699 ± 5129162301) * 10^-8 + msg!("The price is ({} ± {}) * 10^{}", price.price, price.conf, price.exponent); + + Ok(()) +} +``` + + + Users must validate the price update for the appropriate **price + feed** and **timestamp**. `PriceUpdateV2` guarantees that the account contains + a verified price for _some_ price feed at _some_ point in time. There are + various methods on this struct (such as `get_price_no_older_than`) that users + can use to implement the necessary checks. + +If you choose the price feed account integration (see below), you +can use an account address check to validate the price feed ID. + + + +## Write Frontend Code + +There are two different paths to the frontend integration of Pyth prices on Solana. +Developers can choose to use two different types of accounts: + +- **Price feed accounts** hold a sequence of prices for a specific price feed ID that always moves forward in time. + These accounts have a fixed address that your program can depend on. + The Pyth Data Association maintains a set of price feed accounts that are continuously updated. + Such accounts are a good fit for applications that always want to consume the most recent price. +- **Price update accounts** are ephemeral accounts that anyone can create, overwrite, and close. + These accounts are a good fit for applications that want to consume prices for a specific timestamp. + +Both price feed accounts and price update accounts work identically from the perspective of the on-chain program. +However, the frontend integration differs slightly between the two. +Both options are explained in the sections below, and developers should pick the one that is best suited for their use case. + +### Price Feed Accounts + +For developers using price feed accounts, the frontend code needs to pass the relevant price feed **account address** to the transaction. +Price feed accounts are program-derived addresses and thus the account ID for any price feed can be derived automatically. +The `PythSolanaReceiver` class provides a method for deriving this information: + +```typescript copy +import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver"; + +// You will need a Connection from @solana/web3.js and a Wallet from @coral-xyz/anchor to create +// the receiver. +const connection: Connection; +const wallet: Wallet; +const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet }); + +// There are up to 2^16 different accounts for any given price feed id. +// The 0 value below is the shard id that indicates which of these accounts you would like to use. +// However, you may choose to use a different shard to prevent Solana congestion on another app from affecting your app. +const solUsdPriceFeedAccount = pythSolanaReceiver + .getPriceFeedAccountAddress(0, SOL_PRICE_FEED_ID) + .toBase58(); +``` + + + The Price Feed Accounts integration assumes that an off-chain process is + continuously updating each price feed. The Pyth Data Association sponsors + price updates for a subset of commonly used price feeds on shard 0. Please see + [Push Feeds](/price-feeds/core/push-feeds) for a list of push feeds + and their account addresses. + +Additionally, updating a price feed is a +permissionless operation, and anyone can run this process. Please see [Using +Price Pusher](/price-feeds/schedule-price-updates/using-price-pusher) for more +information. Running the Price Pusher can help with reliability and update +feed/shard pairs that are not part of the default schedule. + + + +### Price Update Accounts + +To use price update accounts, the frontend code needs to perform two different tasks: + +1. Fetch price updates from Hermes +2. Post the price updates to Solana and invoke your application logic + +#### Fetch price updates + +Use `PriceServiceConnection` from `@pythnetwork/hermes-client` to fetch Pyth price updates from Hermes: + +```typescript copy +import { HermesClient } from "@pythnetwork/hermes-client"; + +// The URL below is a public Hermes instance operated by the Pyth Data Association. +// Hermes is also available from several third-party providers listed here: +// https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes +const priceServiceConnection = new HermesClient( + "https://hermes.pyth.network/", + {}, +); + +// Hermes provides other methods for retrieving price updates. See +// https://hermes.pyth.network/docs for more information. +const priceUpdateData = ( + await priceServiceConnection.getLatestPriceUpdates( + ["0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"], + { encoding: "base64" }, + ) +).binary.data; + +// Price updates are strings of base64-encoded binary data. Example: +// ["UE5BVQEAAAADuAEAAAADDQJoIZzihVp30/71MXDexqiJDjGpEUEcHj/D06pRiYTPPlRPZKKiVFaZdqiGZ7vvGBj1kK69fKRncCKHXlGyS0LcAQPREzVlm7AcY+X0/hCupv8M5KMhEgOCxq5LxCCKQjL/xwm4jTCJrwkHn/PBaoirnlbHMjxAlwJaFF4RGeE1KRDeAASQIFjfbbobiq2OcSRnK3Ny1NY2Zd012ahIhoWpqxbv4UqDZXLh+bPm4Q14SfO/llRTOmqG6O4v+nfjZa7WNjgxAAZFANqAEooKvijK+476YBITKono+vJ4bSQHUiXOaiGs/zcI6WYGRM0xc6ov2mfCaTuH7mx3ElaLyPGvRX4D9DyHAAf+dPg+NEepwMJI1qPLRcTy0xoz2Yq0k2MuL87gCBsYVlS31atGsQcrXfHr4xcTKKyEUh1tIaOfRbPdX1cvs4D6AAj2/vuKpAgYWhd2gtqHsQLV1vMgq8SKH8wiOmhaMZ06GAQSM1pYLpHZRhYaUQbrUJAeqEeX+qMMqQFMPSSUnEKNAAmCE98NUYbHuEoxJGMDybTGCyDEXCmaNM0q6GT0qrbSmT6NF50yz9CE30WWHNOZzFtK2rCyBYFH2aAp6lQ1JKfmAQpW/wUaOhSdwGiEPWvpY3FWL077i0c4auXQjSQNaDD0cBnmvJTS5R3KxK5aunuUvVAT1mHTnpKHIzNKyu7ICM2zAQvrIFfWRFjVE0zRCvoAcvMpmpS7atWu8VgvklpZh9Qt9xYSO2Yq/asgNsMSQaowXiU0MfjggS+UJ8yWaOpUg18vAAxAMuUlOjNzFj6oPES850YNu2k7PM7AGL8Gb/8+HshkfjG0GsNR8H8/vB8v/iEcaScxQFXwtLT0OSgjWMa0ByknAA7PScKUEP8N7iJKYv6lmEs26DZnxzdpGVZRGqbbC0mxyjY0HqsT0rv2wNvy3MbAtABDMsLumII00cRCKBsZXGlKARCC0NzsKnduLsgGfqxYL4yuf910DKrRp5j+fKLmF2QiB2yVT90ja0782/u6BZZUGRMoA/AWl1qvswBtnlSkHcWEABIp74UFLiiA+MBBvBzhLBxSTKXldiLJ75+U/eqK/ej6qT+I+6S1pzT/ntXdpD25jmQhjtsYEqs/rmgs5U2p4AVRAGYULPcAAAAAABrhAfrtrFhR4yubI7X5QRqMK6xKrj7U3XuBHdGnLqSqcQAAAAAC8IR2AUFVV1YAAAAAAAf6dUkAACcQMZv+5jfvAe6sflX1cL7xu9WWQ9UBAFUA5i32yLSoX+GmfbRNwS3l2zMPesZrctxliv7fD0pBW0MAAAaBiqrXwAAAAADYu55y////+AAAAABmFCz3AAAAAGYULPYAAAaFH6MbAAAAAADcBIdMCre0t06ngCnw+N4IkFpZVqOz9YuwKL+UFdt13ZBtay0YZnkw7QGoaTDCLlsNK1tk1F/qgMyOcYozjOTj41XriIpEPeG2HPYl+u0CKolGlCsz1IDu4w2lyh6LWVaMkEybGz7ih4H2RqCj6BVu182ZqsZgJx9ghzKImAo4cIlWzRTwpm4daAqHa4JEyimFDpFt6UeqvS5TNu2F8W+X+edeiph20EulTI7sx38jwhq5Yc0Mf2ElvFgToGQ806Vs2HynuLwh9OIuTTZh"] +console.log(priceUpdateData); +``` + +Consult [Fetch Price Updates](/price-feeds/core/fetch-price-updates) for more information on fetching price updates from Hermes. + +#### Post price updates + +Finally, post the price update to the Pyth program on Solana. +This step will create the price update account that your application reads from. +Applications typically combine posting the price update and invoking their application into a sequence of transactions. +The `PythSolanaReceiver` class in `@pythnetwork/pyth-solana-receiver` provides a convenient transaction builder to help with this process: + +```typescript copy +import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver"; + +// You will need a Connection from @solana/web3.js and a Wallet from @coral-xyz/anchor to create +// the receiver. +const connection: Connection; +const wallet: Wallet; +const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet }); + +// Set closeUpdateAccounts: true if you want to delete the price update account at +// the end of the transaction to reclaim rent. +const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({ + closeUpdateAccounts: false, +}); +await transactionBuilder.addPostPriceUpdates(priceUpdateData); + +// Use this function to add your application-specific instructions to the builder +await transactionBuilder.addPriceConsumerInstructions( + async ( + getPriceUpdateAccount: (priceFeedId: string) => PublicKey, + ): Promise => { + // Generate instructions here that use the price updates posted above. + // getPriceUpdateAccount() will give you the account for each price update. + return []; + }, +); + +// Send the instructions in the builder in 1 or more transactions. +// The builder will pack the instructions into transactions automatically. +await pythSolanaReceiver.provider.sendAll( + await transactionBuilder.buildVersionedTransactions({ + computeUnitPriceMicroLamports: 50000, + }), + { skipPreflight: true }, +); +``` + +The [SDK documentation](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/solana/sdk/js/pyth_solana_receiver) contains more information about interacting with the Pyth solana receiver contract, including working examples. + + + Posting and verifying price updates currently requires multiple transactions + on Solana. If your usecase requires a single transaction, you can reduce the + verification level of the posted price updates by replacing + `addPostPriceUpdates` by `addPostPartiallyVerifiedPriceUpdates` in the + transaction builder. Please read the + [VerificationLevel](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/solana/pyth_solana_receiver_sdk/src/price_update.rs#L20) + docs to understand more about the data integrity tradeoffs when using + partially verified price updates. + + +## Time-Weighted Average Price (TWAP) + +Pyth also provides Time-Weighted Average Price (TWAP) for Solana applications. TWAP represents the average price over a specified time window, which can be useful for reducing the impact of short-term price volatility. The TWAP window is currently limited to a maximum of 10 minutes (600 seconds). + +### Using TWAP in Solana Programs + +To use TWAP in your Solana program, import the `TwapUpdate` struct from the Pyth Solana receiver SDK. The process for fetching and posting TWAP updates is similar to regular price updates from Hermes. + +```rust copy +use pyth_solana_receiver_sdk::price_update::{TwapUpdate}; + +#[derive(Accounts)] +#[instruction(twap_window_seconds: u64)] +pub struct SampleWithTwap<'info> { + #[account(mut)] + pub payer: Signer<'info>, + // Add this account to any instruction Context that needs TWAP data + pub twap_update: Account<'info, TwapUpdate>, +} +``` + +Update your instruction logic to read the TWAP from the update account: + +```rust copy +pub fn sample_with_twap( + ctx: Context, + twap_window_seconds: u64, +) -> Result<()> { + let twap_update = &mut ctx.accounts.twap_update; + // get_twap_no_older_than will fail if the price update is more than 30 seconds old + let maximum_age: u64 = 30; + // Specify the price feed ID and the window in seconds for the TWAP + let feed_id: [u8; 32] = get_feed_id_from_hex("0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43")?; + let price = twap_update.get_twap_no_older_than( + &Clock::get()?, + maximum_age, + twap_window_seconds, + &feed_id, + )?; + + // Sample output: + // The TWAP price is (7160106530699 ± 5129162301) * 10^-8 + msg!("The TWAP price is ({} ± {}) * 10^{}", price.price, price.conf, price.exponent); + + Ok(()) +} +``` + +### Fetching and Posting TWAP Updates + +To use TWAP updates in your application, you need to fetch them from Hermes and post them to Solana: + +#### Fetch TWAP updates from Hermes + +Use `HermesClient` from `@pythnetwork/hermes-client` to fetch TWAP updates: + +```typescript copy +import { HermesClient } from "@pythnetwork/hermes-client"; + +// The URL below is a public Hermes instance operated by the Pyth Data Association. +// Hermes is also available from several third-party providers listed here: +// https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes +const hermesClient = new HermesClient("https://hermes.pyth.network/", {}); + +// Specify the price feed ID and the TWAP window in seconds (maximum 600 seconds) +const twapWindowSeconds = 300; // 5 minutes +const twapUpdateData = await hermesClient.getLatestTwaps( + ["0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"], // BTC/USD feed ID + twapWindowSeconds, + { encoding: "base64" }, +); + +// TWAP updates are strings of base64-encoded binary data +console.log(twapUpdateData.binary.data); +``` + +For a complete example of fetching TWAP updates from Hermes, see the [HermesClient example script](https://github.com/pyth-network/pyth-crosschain/blob/main/apps/hermes/client/js/src/examples/HermesClient.ts) in the Pyth crosschain repository. + +#### Post TWAP updates to Solana + +Use `PythSolanaReceiver` to post the TWAP updates and consume them in your application: + +```typescript copy +import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver"; + +// You will need a Connection from @solana/web3.js and a Wallet from @coral-xyz/anchor +const connection: Connection; +const wallet: Wallet; +const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet }); + +// Create a transaction builder +const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({ + closeUpdateAccounts: false, +}); + +// Add the TWAP update to the transaction +await transactionBuilder.addPostTwapUpdates(twapUpdateData.binary.data); + +// Add your application's instructions that use the TWAP update +await transactionBuilder.addTwapConsumerInstructions( + async ( + getTwapUpdateAccount: (priceFeedId: string) => PublicKey, + ): Promise => { + // Generate instructions here that use the TWAP updates posted above + // getTwapUpdateAccount() will give you the account for each TWAP update + return []; // Replace with your actual instructions + }, +); + +// Send the instructions +await pythSolanaReceiver.provider.sendAll( + await transactionBuilder.buildVersionedTransactions({ + computeUnitPriceMicroLamports: 50000, + }), + { skipPreflight: true }, +); +``` + +For a complete example of posting TWAP updates to Solana, see the [post_twap_update.ts example script](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/solana/sdk/js/pyth_solana_receiver/examples/post_twap_update.ts) in the Pyth crosschain repository. + +## Additional Resources + +You may find these additional resources helpful for developing your Solana application. + +### Example Application + +See an end-to-end example of using Pyth Network prices in the [SendUSD Solana Demo App](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/solana/send_usd). The app allows users to send a USD-denominated amount of SOL using either spot prices or TWAP prices. +It demonstrates how to fetch price data from Hermes from a frontend, post it to the Solana blockchain, and consume it from a smart contract. + +The example includes: + +- A React frontend for interacting with the contract +- Solana programs that consumes spot price updates (Price Update Accounts) and time-averaged price updates (TWAP Accounts) +- Complete transaction building for posting and consuming price data diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/stacks.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/stacks.mdx new file mode 100644 index 0000000000..0106cd4a1c --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/stacks.mdx @@ -0,0 +1,176 @@ +--- +title: How to Use Real-Time Data in Stacks Applications +description: Consume Pyth Network prices in Stacks applications +slug: /price-feeds/core/use-real-time-data/pull-integration/stacks +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +[Stacks](https://www.stacks.co/) is a layer 2 network on Bitcoin. It brings programmability and decentralized applications (dApps) to Bitcoin without modifying Bitcoin itself. Stacks lets developers build apps, smart contracts, NFTs, and DeFi on top of Bitcoin — while using Bitcoin as the settlement and security layer. + +This guide explains how to use real-time Pyth data in [Clarity](https://clarity-lang.org/) smart contracts on Stacks. + +## Write Contract Code + +The Pyth protocol integration for Stacks is available as a Beta on both testnet and mainnet networks, to help developers test, give feedback, and ensure the reliability and stability of the integration. +Unlike other smart contract languages, there is no importing modules into Clarity smart contracts for certain security reasons. So the Pyth integration on Stacks is implemented as its own set of Clarity contracts where developers will invoke a `contract-call?` to the main Pyth Clarity [contract](https://explorer.hiro.so/txid/SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4?chain=mainnet). + + + Currently, the Pyth protocol integration is currently maintained by Trust + Machines. It currently supports real-time price feeds for BTC, STX, ETH, and + USDC. To request more price feeds, open an issue in Trust Machine's Pyth + maintained repo [here](https://github.com/Trust-Machines/stacks-pyth-bridge). + + +### Read BTC prices from a Clarity smart contract + +For our example, we will imagine a contract that mints an NFT in exchange for $100 of sBTC. In order to determine the USD value of a user's sBTC amount, we'll need to use Pyth. Since market pricing for sBTC isn't supported currently, we'll use the price data from the BTC/USD price feed. + + + The maintained Pyth integration contract for Stacks is called + [`.pyth-oracle-v4`](https://explorer.hiro.so/txid/SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4?chain=mainnet). + This contract serves as the main entry point for updating and getting price + feed data. + + +You'll notice in the Clarity snippet below we open up `let` bindings of our function to: + +1. Verify & update the BTC price feed with its latest VAA message (more on how to pull the VAA later in this guide). This is a means of participating in the pull price update model. +2. Getting a fresh instance of the updated price data for BTC. + +```clarity +;; --snip-- +(define-public (join-the-benjamin-club (price-feed-bytes (buff 8192))) + (let ( + ;; To verify & update price feeds is to participate in the pull price model of Pyth's decentralization. + ;; A VAA signed message is pulled from Wormhole via the Hermes API. This VAA signed message is what + ;; gets passed into this function to verify & update the price data of a particular price feed. + (update-status (try! (contract-call? 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4 + verify-and-update-price-feeds price-feed-bytes { + pyth-storage-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-storage-v4, + pyth-decoder-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-pnau-decoder-v3, + wormhole-core-contract: 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.wormhole-core-v4, + }))) + ;; The price data returned will be fresh from the VAA signed message data we passed in above. + (price-data (try! (contract-call? 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4 + get-price + ;; The official BTC price feed id. + 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43 + 'SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-storage-v4 + ))) + ;; --snip-- +``` + +After updating & verifying the price feed in question, and then getting the updated price feed data, we'll need to handle the price feed data and its properties. +The price feed data returned from invoking the `get-price` function of the `.pyth-oracle-v4` contract looks like the below: + +```bash +{ + price-identifier: 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43, + price: 10603557773590, + conf: u3776653890, + ema-price: 10602069900000, + ema-conf: u4062895700, + expo: -8, + publish-time: u1750425711, + prev-publish-time: u1750425710 +} +``` + +With the price feed data, we can adjust the price based on the `expo` property. Price feeds represent numbers in a fixed-point format. So in the above returned price feed data, the price of `10603557773590` and given `expo` of `-8` should be formatted as `106035`. The same exponent is used for both the price and confidence interval. + +We can then determine the USD amount of sBTC the user owns and decide if it is enough to mint a `benjamin-nft` for $100 worth of sBTC. Benjamin is in reference to Benjamin Franklin being the face of a one hundred dollar bill, get it? + +```clarity +;; --snip -- + ;; Price feeds represent numbers in a fixed-point format. The expo property tells us + ;; at what certain position is the decimal point implicity fixed. + (price-denomination (pow 10 (* (get expo price-data) -1))) + ;; We'll adjust the price to its normal decimal representation. + (adjusted-price (to-uint (/ (get price price-data) price-denomination))) + ;; Get the user's current sBTC balance. + (user-sbtc-balance (unwrap! + (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token + get-balance-available tx-sender + ) + ERR_READING_SBTC_BALANCE + )) + ) + ;; Determine if the user has at least $100 worth of sBTC to join the Benjamin Club. + (if (> (/ (* user-sbtc-balance adjusted-price) (to-uint price-denomination)) + COST-OF-BENJAMIN-NFT + ) + (let ((hundred-dollars-in-sbtc (/ (* COST-OF-BENJAMIN-NFT (to-uint price-denomination)) adjusted-price))) + (try! (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token + transfer hundred-dollars-in-sbtc tx-sender (as-contract tx-sender) + none + )) + (contract-call? .nft-contract mint tx-sender) + ) + ERR_NOT_ENOUGH_SBTC + ) + ) +) +``` + + + The `verify-and-update-price-feeds` of the `.pyth-oracle-v4` contract applies + a fee of 1 uSTX, or 1 micro-stx, which is 0.000001 STX. + + +Alternatively, developers can just invoke the `read-price-feed` public function of the `pyth-oracle-v4.clar` contract. This will simply return the price feed from the last updated feed. But it's always encouraged to determine if a staleness check is viable for your application. + +## Write Front-End Code + +In your front-end application code, you can install and use the methods brought by Pyth Network's `hermes-client` Javascript SDK to fetch the latest price update, known as a VAA (Verified Action Approvals) message. + +```javascript copy +import { HermesClient } from "@pythnetwork/hermes-client"; + +// --snip-- +async function handleFetchLatestVaa() { + const connection = new HermesClient("https://hermes.pyth.network", {}); + + const priceIds = [ + "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + ]; + + const priceUpdates = await connection.getLatestPriceUpdates(priceIds); + let latestVaaHex = `0x${priceUpdates.binary.data[0]}`; + + return latestVaaHex; +} +// --snip-- +``` + +The binary data returned from the Pyth SDK will already be in hexadecimal format. We'll then take this hexadecimal VAA message and pass it into our Clarity function as an argument. + +Using Stacks Connect of the [stacks.js](https://github.com/hirosystems/stacks.js) monorepo, we'll open up a stx_callContract request and invoke our public function while passing in the latestVaaHex as the function argument. + +```javascript copy +let latestVaaHex = await handleFetchLatestVaa(); + +let postCond1 = Pc.principal("SP1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRCBGD7R") + .willSendLte(1) + .ustx(); + +const response = await request("stx_callContract", { + contract: `SP1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRCBGD7R.benjamin-club`, + functionName: "join-the-benjamin-club", + functionArgs: [Cl.bufferFromHex(latestVaaHex)], + network: "mainnet", + postConditions: [postCond1], + postConditionMode: "deny", +}); +``` + +If you noticed, we set a post-condition statement of our user transferring less than or equal to 1 uSTX, which is 0.000001 STX. This is because the `verify-and-update-price-feeds` of the `.pyth-oracle-v4` contract applies a fee for this. Setting a separate post-condition statement on the actual sbtc token transfer in our example will also be needed. Beforehand, you could invoke the `decode-price-feeds` function with the `latestVaaHex` to simply have the contained price data decoded and returned. From there you could pre-determine the estimated amount of sbtc tokens to be transferred and set in a separate post-condition. + +## Additional Resources + +You may find these additional resources helpful for developing your Stacks application with Pyth. + +- **[Hiro Docs](https://docs.hiro.so/resources/guides/using-pyth-price-feeds):** Check out the dedicated guide for using Pyth in Stacks applications in Hiro's documentation. In this guide you'll see a visual architecture overview of using Pyth in Stacks, how you can test your implementation, how to fetch VAAs on the front-end, learn best practices, and more. +- **[Hiro How-To Tutorial](https://youtu.be/eybqQVRh_hw?si=KNfUp3RS3CnaST91):** Watch the dedicated video tutorial on using Pyth in Stacks and learn how a major Stacks DeFi app, Granite, is using Pyth. +- **[Trust Machine's Pyth Github](https://github.com/Trust-Machines/stacks-pyth-bridge):** Check out the open-source repo for the Pyth integration Clarity contracts. +- **[pyth-oracle-v4.clar](https://explorer.hiro.so/txid/SP1CGXWEAMG6P6FT04W66NVGJ7PQWMDAC19R7PJ0Y.pyth-oracle-v4?chain=mainnet):** The latest Pyth integration contract on Stacks' mainnet. diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/starknet.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/starknet.mdx new file mode 100644 index 0000000000..d95fdc3582 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/starknet.mdx @@ -0,0 +1,179 @@ +--- +title: How to Use Real-Time Data in Starknet Contracts +description: Consume Pyth Network prices in Starknet applications +slug: /price-feeds/core/use-real-time-data/pull-integration/starknet +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Tab, Tabs } from "fumadocs-ui/components/tabs"; + +This guide explains how to use real-time Pyth data in Starknet contracts. + +## Install the Pyth SDK + +Use the following dependency in your `Scarb.toml` file to use the latest Pyth Starknet package: + +```toml copy +[dependencies] +pyth = { git = "https://github.com/pyth-network/pyth-crosschain.git", tag = "pyth-starknet-contract-v0.1.0"} +``` + +Pyth also provides a javascript SDK to interact with the Pyth contract on Starknet. You can install it using the following command: + + + + ```bash copy npm install --save @pythnetwork/pyth-starknet-js ``` + + + ```bash copy yarn add @pythnetwork/pyth-starknet-js ``` + + + +## Write Contract Code + +The code snippet below provides an example module fetching the STRK/USD price from Pyth price feeds: + +```rust copy +use starknet::ContractAddress; +use pyth::ByteBuffer; + +#[starknet::interface] +pub trait IExampleContract { + // pyth_price_update is the price update data from Pyth to update the price feeds. + // It should be passed as a ByteBuffer. + fn example_method( + ref self: T, pyth_price_update: ByteBuffer + ); +} + +#[starknet::contract] +mod example_contract { + use core::panic_with_felt252; + use starknet::{ContractAddress, get_caller_address, get_contract_address}; + use pyth::{ByteBuffer, IPythDispatcher, IPythDispatcherTrait, UnwrapWithFelt252}; + use openzeppelin::token::erc20::interface::{IERC20CamelDispatcherTrait, IERC20CamelDispatcher}; + + const MAX_PRICE_AGE: u64 = 3600; // 1 hour + // Storage to store the Pyth contract address, the ERC20 contract address representing ETH, and the ETH/USD price feed ID. + #[storage] + struct Storage { + pyth_address: ContractAddress, + strk_erc20_address: ContractAddress, + } + + // Constructor to initialize the contract storage. + // * @param pyth_address: The address of the Pyth contract on Starknet. + // * @param strk_erc20_address: The address of the ERC20 contract representing STRK on Starknet. + #[constructor] + fn constructor( + ref self: ContractState, + pyth_address: ContractAddress, + strk_erc20_address: ContractAddress, + ) { + self.pyth_address.write(pyth_address); + self.strk_erc20_address.write(strk_erc20_address); + } + + #[abi(embed_v0)] + impl ExampleContract of super::IExampleContract { + fn example_method( + ref self: ContractState, + pyth_price_update: ByteBuffer + ) { + let pyth = IPythDispatcher { contract_address: self.pyth_address.read() }; + let strk_erc20 = IERC20CamelDispatcher { + contract_address: self.strk_erc20_address.read() + }; + let caller = get_caller_address(); + let contract = get_contract_address(); + + // Get the fee required to update the Pyth price feeds. + let pyth_fee = pyth.get_update_fee(pyth_price_update.clone(), strk_erc20.contract_address); + if !strk_erc20.transferFrom(caller, contract, pyth_fee) { + panic_with_felt252('insufficient allowance for fee'); + } + if !strk_erc20.approve(pyth.contract_address, pyth_fee) { + panic_with_felt252('approve failed'); + } + + // Submit a pyth_price_update to the Pyth contract to update the on-chain price. + pyth.update_price_feeds(pyth_price_update); + + // Read the current price from a price feed. + // STRK/USD price feed ID + // The complete list of feed IDs is available at https://docs.pyth.network/price-feeds/price-feeds + let strk_usd_price_id = + 0x6a182399ff70ccf3e06024898942028204125a819e519a335ffa4579e66cd870; + let price = pyth + .get_price_no_older_than(strk_usd_price_id, MAX_PRICE_AGE) + .unwrap_with_felt252(); + let _: u64 = price.price.try_into().unwrap(); // Price in u64 + } + } +} +``` + +The pyth_price_update argument contains verified prices from Pyth. +Calling pyth.update_price_feeds with this value updates the on-chain Pyth price and ensures your application has recent price data. +The pyth_price_update 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 pyth_price_update. + + + Unlike Ethereum, there is no native token on Starknet. You cannot pass tokens + implicitly when calling functions. Moreover, there is no concept of a + designated payer account, unlike Solana. In Starknet, all token transfers must + be performed explicitly by calling functions on the token's ERC20 contract. + Regarding the Pyth contract on Starknet, the caller must approve the fee + transfer before calling `update_price_feeds` or using similar methods. You can + use **STRK** or **ETH** to pay the fee, but STRK is preferred. The fee is + currently set to the minimum possible value (1e-18 STRK, 1 WEI). + + +The code snippet above does the following things: + +1. Call `pyth.get_update_fee` to get the fee required to update the Pyth price feeds. +1. Call `pyth.update_price_feeds` and pass `pyth_price_update` to update the Pyth price feeds. +1. Call `pyth.get_price_no_older_than` to read the price, providing the [price feed ID](/price-feeds/core/price-feeds) you wish to read. + +### Write Client Code + +The code snippet below provides an example of how to fetch price updates and convert to `ByteBuffer` for Starknet using the `pyth-starknet-js` in JavaScript: + +```ts {16} copy +import { PriceServiceConnection } from "@pythnetwork/price-service-client"; +import { ByteBuffer } from "@pythnetwork/pyth-starknet-js"; +// The URL below is a public Hermes instance operated by the Pyth Data Association. +// Hermes is also available from several third-party providers listed here: +// https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes +const connection = new PriceServiceConnection("https://hermes.pyth.network", { + priceFeedRequestConfig: { + binary: true, + }, +}); + +const priceId = + "0x6a182399ff70ccf3e06024898942028204125a819e519a335ffa4579e66cd870"; // STRK/USD + +// Get the latest values of the price feeds as json objects. +const currentPrices = await connection.getLatestPriceFeeds([priceId]); + +// Convert the price update to Starknet format. +const pythUpdate = ByteBuffer.fromBase64(currentPrices[0].vaa); +``` + + + Price updates must be converted to `ByteBuffer` before being passed on to the + Pyth contract on Starknet. Use the `ByteBuffer` type from + `@pythnetwork/pyth-starknet-js` package as shown above. + + +## Additional Resources + +You may find these additional resources helpful for developing your Starknet application. + +### Interface + +The [Starknet Interface](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/starknet/contracts/src/pyth/interface.cairo#L9) provides a list of functions that can be called on the Pyth contract deployed on Starknet. + +### Example Applications + +- [Send-USD](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/starknet), which updates and consumes STRK/USD price feeds on Starknet to send USD to a recipient. diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/sui.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/sui.mdx new file mode 100644 index 0000000000..3845a53206 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/sui.mdx @@ -0,0 +1,252 @@ +--- +title: How to Use Real-Time Data in Sui Contracts +description: Consume Pyth Network prices in Sui applications +slug: /price-feeds/core/use-real-time-data/pull-integration/sui +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Tab, Tabs } from "fumadocs-ui/components/tabs"; + +This guide explains how to use real-time Pyth data in Sui applications. + +## Install Pyth SDK + +Use the following dependency in your `Move.toml` file to use the latest Pyth Sui package and its dependencies: + + + +```bash copy +[dependencies.Pyth] +git = "https://github.com/pyth-network/pyth-crosschain.git" +subdir = "target_chains/sui/contracts" +rev = "sui-contract-mainnet" + +[dependencies.Wormhole] +git = "https://github.com/wormhole-foundation/wormhole.git" +subdir = "sui/wormhole" +rev = "sui/mainnet" + +# Pyth is locked into this specific `rev` because the package depends on Wormhole and is pinned to this version. + +[dependencies.Sui] +git = "https://github.com/MystenLabs/sui.git" +subdir = "crates/sui-framework/packages/sui-framework" +rev = "041c5f2bae2fe52079e44b70514333532d69f4e6" + +```` + + +```bash copy +[dependencies.Pyth] +git = "https://github.com/pyth-network/pyth-crosschain.git" +subdir = "target_chains/sui/contracts" +rev = "sui-contract-testnet" + +[dependencies.Wormhole] +git = "https://github.com/wormhole-foundation/wormhole.git" +subdir = "sui/wormhole" +rev = "sui/testnet" + +# Pyth is locked into this specific `rev` because the package depends on Wormhole and is pinned to this version. + +[dependencies.Sui] +git = "https://github.com/MystenLabs/sui.git" +subdir = "crates/sui-framework/packages/sui-framework" +rev = "041c5f2bae2fe52079e44b70514333532d69f4e6" +```` + + + + +Pyth also provides a javascript SDK to construct transaction blocks that update price feeds: + + + +```bash +# NPM +npm install --save @pythnetwork/pyth-sui-js + +# Yarn + +yarn add @pythnetwork/pyth-sui-js + +```` + + + +## Write Contract Code + +The code snippet below provides a general template for what your contract code should look like: + +```rust {18} copy +/// Module: oracle +module oracle::oracle; + +use sui::clock::Clock; +use pyth::price_info; +use pyth::price_identifier; +use pyth::price; +use pyth::i64::I64; +use pyth::pyth; +use pyth::price_info::PriceInfoObject; + +const E_INVALID_ID: u64 = 1; + +public fun get_sui_price( + // Other arguments + clock: &Clock, + price_info_object: &PriceInfoObject, +): I64 { + let max_age = 60; + + // Make sure the price is not older than max_age seconds + let price_struct = pyth::get_price_no_older_than(price_info_object, clock, max_age); + + // Check the price feed ID + let price_info = price_info::get_price_info_from_price_info_object(price_info_object); + let price_id = price_identifier::get_bytes(&price_info::get_price_identifier(&price_info)); + + // SUI/USD price feed ID + // The complete list of feed IDs is available at https://docs.pyth.network/price-feeds/price-feeds + // Note: Sui uses the Pyth price feed ID without the `0x` prefix. + let testnet_sui_price_id = x"50c67b3fd225db8912a424dd4baed60ffdde625ed2feaaf283724f9608fea266"; + assert!(price_id == testnet_sui_price_id, E_INVALID_ID); + + // Extract the price, decimal, and timestamp from the price struct and use them. + let _decimal_i64 = price::get_expo(&price_struct); + let price_i64 = price::get_price(&price_struct); + let _timestamp_sec = price::get_timestamp(&price_struct); + + price_i64 +} +```` + +One can consume the price by calling `pyth::get_price` abovementioned or other utility functions on the `PriceInfoObject` in the Move module + +The code snippet below provides an example of how to update the Pyth price feeds: + +```ts copy +import { + SuiPythClient, + SuiPriceServiceConnection, +} from "@pythnetwork/pyth-sui-js"; +import { SuiClient } from "@mysten/sui/client"; +import { Transaction } from "@mysten/sui/transactions"; +import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"; + +/// Step 1: Get the off-chain data. +const connection = new SuiPriceServiceConnection( + "https://hermes-beta.pyth.network", // [!] Only for Sui Testnet + // "https://hermes.pyth.network/", // Use this for Mainnet + { + // Provide this option to retrieve signed price updates for on-chain contracts! + priceFeedRequestConfig: { + binary: true, + }, + }, +); +const priceIDs = [ + // You can find the IDs of prices at https://docs.pyth.network/price-feeds/price-feeds + "0x50c67b3fd225db8912a424dd4baed60ffdde625ed2feaaf283724f9608fea266", // SUI/USD price ID +]; +const priceUpdateData = await connection.getPriceFeedsUpdateData(priceIDs); + +/// Step 2: Submit the new price on-chain and verify it using the contract. +const suiClient = new SuiClient({ url: "https://fullnode.testnet.sui.io:443" }); + +// Fixed the StateIds using the CLI example extracting them from +// here: https://docs.pyth.network/price-feeds/contract-addresses/sui +const pythTestnetStateId = + "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c"; // Testnet +const wormholeTestnetStateId = + "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790"; // Testnet + +const pythClient = new SuiPythClient( + suiClient, + pythTestnetStateId, + wormholeTestnetStateId, +); + +const transaction = new Transaction(); + +/// By calling the updatePriceFeeds function, the SuiPythClient adds the necessary +/// transactions to the transaction block to update the price feeds. +const priceInfoObjectIds = await pythClient.updatePriceFeeds( + transaction, + priceUpdateData, + priceIDs, +); + +const suiPriceObjectId = priceInfoObjectIds[0]; +if (!suiPriceObjectId) { + throw new Error("suiPriceObjectId is undefined"); +} + +/// This is the package id that we receive after publishing `oracle` contract from the previous step. +const testnetExampleContractPackageId = + "0x42d05111a160febe4144338647e0b7a80daea459c765c1e29a7a6198b235f67c"; +const CLOCK = + "0x0000000000000000000000000000000000000000000000000000000000000006"; +transaction.moveCall({ + target: `${testnetExampleContractPackageId}::oracle::get_sui_price`, + arguments: [transaction.object(CLOCK), transaction.object(suiPriceObjectId)], +}); +transaction.setGasBudget(1000000000); + +const keypair = Ed25519Keypair.fromSecretKey( + process.env.ADMIN_SECRET_KEY!.toLowerCase(), +); +const result = await suiClient.signAndExecuteTransaction({ + transaction, + signer: keypair, + options: { + showEffects: true, + showEvents: true, + }, +}); +``` + +By calling the `updatePriceFeeds` function, the `SuiPythClient` adds the necessary transactions to the transaction block to update the price feeds. + + + +Your Sui Move module **should NOT** have a hard-coded call to `pyth::update_single_price_feed.` In other words, a contract should **never call** the Sui Pyth `pyth::update_single_price_feed` entry point. Instead, it should be called directly from client code (e.g., Typescript or Rust). + +When Sui contracts are [upgraded](https://docs.sui.io/build/package-upgrades), the address changes, which makes the old address no longer valid. If your module has a hard-coded call to `pyth::update_single_price_feed` living at a fixed call-site, it may eventually get bricked due to how Pyth upgrades are implemented. (Pyth only allow users to interact with the most recent package version for security reasons). + +Therefore, you should build a [Sui programmable transaction](https://docs.sui.io/build/prog-trans-ts-sdk) that first updates the price by calling `pyth::update_single_price_feed` at the latest call-site from the client-side and then call a function in your contract that invokes `pyth::get_price` on the `PriceInfoObject` to get the recently updated price. +You can use `SuiPythClient` to build such transactions and handle all the complexity of updating the price feeds. + +Consult [Fetch Price Updates](/price-feeds/core/fetch-price-updates) for more information on how to fetch the `pyth_price_update`. + + + +## Additional Resources + +You may find these additional resources helpful for developing your Sui application. + +### CLI Example + +[This example](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/sui/cli) shows how to update prices on a Sui network. It does the following: + +1. Fetches update data from Hermes for the given price feeds. +1. Call the Pyth Sui contract with a price update. + +You can run this example with `npm run example-relay`. A full command that updates prices on the Sui testnet looks like this: + +```bash +export SUI_KEY=YOUR_PRIV_KEY; +npm run example-relay -- --feed-id "5a035d5440f5c163069af66062bac6c79377bf88396fa27e6067bfca8096d280" \ +--hermes "https://hermes-beta.pyth.network" \ +--full-node "https://fullnode.testnet.sui.io:443" \ +--pyth-state-id "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c" \ +--wormhole-state-id "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790" +``` + +### Contract Addresses + +Consult [Sui Contract Addresses](../../contract-addresses/sui) to find the package IDs. + +### Pyth Price Feed IDs + +Consult [Pyth Price Feed IDs](/price-feeds/core/price-feeds) to find Pyth price feed IDs for various assets. diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/ton.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/ton.mdx new file mode 100644 index 0000000000..7c16e308d2 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/pull-integration/ton.mdx @@ -0,0 +1,340 @@ +--- +title: How to Use Real-Time Data in TON Contracts +description: Consume Pyth Network prices in TON applications +slug: /price-feeds/core/use-real-time-data/pull-integration/ton +--- + +import { Callout } from "fumadocs-ui/components/callout"; +import { Tab, Tabs } from "fumadocs-ui/components/tabs"; + +This guide explains how to use real-time Pyth data in TON applications. + +## Install the Pyth SDK + +Install the Pyth TON SDK and other necessary dependencies using npm: + + + +```bash copy +npm install @pythnetwork/pyth-ton-js @pythnetwork/hermes-client @ton/core @ton/ton @ton/crypto +``` + + +```bash copy +yarn add @pythnetwork/pyth-ton-js @pythnetwork/hermes-client @ton/core @ton/ton @ton/crypto +``` + + + +## Write Contract Code + +The code snippet below provides an example sending a message to the Pyth price feed contract and call the `parse_price_feed_updates` method: + +```rust copy + ;; Create message to Pyth contract according to schema + cell msg = begin_cell() + .store_uint(0x18, 6) ;; nobounce + .store_slice(ctx_pyth_address) ;; pyth contract address + .store_coins(forward_amount) ;; forward amount minus fees + .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) ;; default message headers + .store_uint(PYTH_OP_PARSE_PRICE_FEED_UPDATES, 32) ;; pyth opcode + .store_ref(price_update_data) ;; update data + .store_ref(price_ids) ;; price feed IDs + .store_uint(now() - 100, 64) ;; min_publish_time + .store_uint(now() + 100, 64) ;; max_publish_time + .store_slice(my_address()) ;; target address (this contract) + .store_ref(custom_payload) ;; custom payload with recipient and amount + .end_cell(); + + send_raw_message(msg, 0); +``` + +## Write Client Code + +The following code snippet demonstrates how to fetch price updates, interact with the Pyth contract on TON, and update price feeds: + +```typescript copy +import { TonClient, Address, WalletContractV4 } from "@ton/ton"; +import { toNano } from "@ton/core"; +import { mnemonicToPrivateKey } from "@ton/crypto"; +import { HermesClient } from "@pythnetwork/hermes-client"; +import { + PythContract, + PYTH_CONTRACT_ADDRESS_TESTNET, + calculateUpdatePriceFeedsFee, +} from "@pythnetwork/pyth-ton-js"; +const BTC_PRICE_FEED_ID = + "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; +async function main() { + // Initialize TonClient + const client = new TonClient({ + endpoint: "https://testnet.toncenter.com/api/v2/jsonRPC", + apiKey: "your-api-key-here", // Optional + }); + // Create PythContract instance + const contractAddress = Address.parse(PYTH_CONTRACT_ADDRESS_TESTNET); + const contract = client.open(PythContract.createFromAddress(contractAddress)); + // Get current guardian set index + const guardianSetIndex = await contract.getCurrentGuardianSetIndex(); + console.log("Guardian Set Index:", guardianSetIndex); + // Get BTC price from TON contract + const price = await contract.getPriceUnsafe(BTC_PRICE_FEED_ID); + console.log("BTC Price from TON contract:", price); + // Fetch latest price updates from Hermes + const hermesEndpoint = "https://hermes.pyth.network"; + const hermesClient = new HermesClient(hermesEndpoint); + const priceIds = [BTC_PRICE_FEED_ID]; + const latestPriceUpdates = await hermesClient.getLatestPriceUpdates( + priceIds, + { encoding: "hex" } + ); + console.log("Hermes BTC price:", latestPriceUpdates.parsed?.[0].price); + // Prepare update data + const updateData = Buffer.from(latestPriceUpdates.binary.data[0], "hex"); + console.log("Update data:", updateData); + // Get update fee + const updateFee = await contract.getUpdateFee(updateData); + console.log("Update fee:", updateFee); + const totalFee = + calculateUpdatePriceFeedsFee(BigInt(updateFee)) + BigInt(updateFee); + // Update price feeds + const mnemonic = "your mnemonic here"; + const key = await mnemonicToPrivateKey(mnemonic.split(" ")); + const wallet = WalletContractV4.create({ + publicKey: key.publicKey, + workchain: 0, + }); + const provider = client.open(wallet); + await contract.sendUpdatePriceFeeds( + provider.sender(key.secretKey), + updateData, + totalFee + ); + console.log("Price feeds updated successfully."); +} +main().catch(console.error); +``` + +This code snippet does the following: + +1. Initializes a `TonClient` and creates a `PythContract` instance. +2. Retrieves the current guardian set index and BTC price from the TON contract. +3. Fetches the latest price updates from Hermes. +4. Prepares the update data and calculates the update fee. +5. Updates the price feeds on the TON contract. + +## Patterns for Providing Pyth Data to Your Contract + +There are typically two main scenarios: either you call a method supplying TON, or you transfer jettons. + +- **TON proxy**: `User → Pyth → EVAA Master → ... (further processing)` + Use this method if you only need to send TON to your contract or simply call a contract method, without involving jettons. + +- **Jetton on-chain getter**: `User → Jetton Wallet → EVAA Master → Pyth → EVAA Master → ... (further processing)` + In this pattern, your contract first receives the Pyth data, then forwards it to the Pyth contract for validation, and finally gets the validated prices back. + This approach is useful when you want to transfer jettons to your contract while also providing price data. + + This data flow is simplified. In reality, the "Jetton Wallet" step consists + of a sequence of transactions: User's jetton wallet → EVAA jetton wallet → + EVAA master. These internal details are omitted here to highlight the main + flow and the interaction with Pyth. + + +They both are demonstrated in the [Pyth Connector example](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/ton/pyth-connector).
+These same patterns are also used in the [EVAA Protocol code](https://github.com/evaafi/contracts/tree/v8) for implementing following operations: + +- Pyth proxy pattern: liquidate TON / supply_withdraw TON. +- Onchain-getter pattern: liquidate jetton / supply_withdraw jetton. + +Choose the pattern that best fits your use case and how you want to handle assets and price updates in your application. + +Each operation described above can result in either a successful outcome or an error. It is important to consider and handle both scenarios for every pattern. + +### Pyth proxy: Success + +#### EVAA flow + +In the EVAA protocol, the operations that implement the Pyth proxy pattern are `liquidate (TON)` and `supply_withdraw (TON)`. In these cases, the user sends a request to the Pyth contract using the native TON asset. As a result of the operation, the user may receive either TON or JETTON tokens back, depending on the outcome of the transaction. + +```mermaid +sequenceDiagram + autonumber + participant U as User + participant P as Pyth Contract + participant M as EVAA Master + + note over M: master.fc:121 — received from Pyth (op 0x5) + U->>P: op 0x5 parse_price_feed_updates (price feeds + update data)
payload (op 0x3 liquidate_master | 0x4 supply_withdraw_master) + note right of U: send request to Pyth Contract with update data and operation payload
destination address is EVAA Master contract + P-->>M: op 0x5 parse_price_feed_updates (price feeds + prices)
payload (op 0x3 liquidate_master | 0x4 supply_withdraw_master) + note right of P: Pyth Contract validates update data and
sends prices with payload to EVAA Master contract + note over M: EVAA Master validates sender
parses payload and
processes the transaction +``` + +- Related code (GitHub): + - [entry for the Pyth message: master.fc](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/master.fc#L121) + - [process the supply_withdraw operation (TON): master.fc](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/master.fc#L192-L211) + - [process the liquidate operation (TON): master.fc](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/master.fc#L171-L190) + +#### Pyth Connector flow + +The Pyth Connector example also has a similar flow. It has two main operations: proxy and onchain-getter. +They have no practical purpose other than to demonstrate the patterns described above. +The data flow is practically the same as the EVAA protocol, only operation codes are different. + +```mermaid +sequenceDiagram + autonumber + participant U as User + participant P as Pyth Contract + participant M as Pyth Connector + + note over M: pyth_connector.fc:78 — received from Pyth (op 0x5) + U->>P: op 0x5 parse_price_feed_updates (price feeds + update data)
payload (op 0x4 connector_proxy_operation) + note right of U: send request to the Pyth Contract with update data and operation payload
destination address is the Pyth Connector contract + P-->>M: op 0x5 parse_price_feed_updates (price feeds + prices)
payload (op 0x4 connector_proxy_operation) + note right of P: Pyth Contract validates update data and
sends prices with payload to Pyth Connector contract + note over M: Pyth Connector validates sender
parses payload and
processes the transaction +``` + +- Related code (GitHub): + - [entry for the Pyth message: pyth-connector.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/pyth_connector.fc#L78) + - [detect the connector_proxy_operation: pyth-connector.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/pyth_connector.fc#L97) + - [process the connector_proxy_operation: proxy_operation.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/operations/proxy_operation.fc#L17-L40) + +### Pyth proxy: Error handling + +In the Pyth proxy pattern, when an error occurs (i.e., Pyth cannot process the request and sends a `response_error` with op 0x10002), the error report is sent directly back to the user who initiated the transaction, not to a contract. This is different from the on-chain getter pattern, where the error is returned to the EVAA Master contract for further handling and potential refund logic. In the proxy case, the user receives the error response from the Pyth contract, including the error code and the original query ID, allowing the user to identify and handle the failure on their side. + +```mermaid +sequenceDiagram + autonumber + participant U as User + participant P as Pyth Contract + + U->>P: request + P-->>U: response_error (op 0x10002) with error_code and query_id +``` + +### Pyth onchain-getter: Success + +#### EVAA flow + +```mermaid +sequenceDiagram + autonumber + participant U as User + participant JW as Jetton Wallet + participant M as EVAA Master + participant P as Pyth Contract + + U->>JW: op transfer_jetton, forward_payload
(liquidate_master_jetton | supply_withdraw_master_jetton) + note right of U: transfer jetton with forward payload: + JW->>M: op transfer_notification, forward_payload
(liquidate_master_jetton | supply_withdraw_master_jetton) + note right of JW: transfer notification with forward payload: + M->>P: op 0x5 parse_price_feed_updates + update data + target feeds
+ payload(liquidate_master_jetton_process | supply_withdraw_master_jetton_process) + P-->>M: op 0x5 parse_price_feed_updates(price feeds + prices)
+ payload(liquidate_master_jetton_process | supply_withdraw_master_jetton_process) + note over P: Pyth Contract validates update data and
sends prices with payload to EVAA Master contract + note over M: EVAA Master validates sender
parses payload and
processes the transaction +``` + +- Related code (GitHub): + - [entry for jetton-transfer notification: master.fc](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/master.fc#L502) + - [request to Pyth (op liquidate_jetton)](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/core/master-liquidate.fc#L728-L742) + - [request to Pyth (op supply_withdraw jetton)](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/core/master-supply-withdrawal.fc#L446-L461) + - [entry point for Pyth response: master.fc (op pyth_parse_price_feed_updates)](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/master.fc#L121) + - [handle pyth response: liquidate_jetton and supply_withdraw_jetton](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/master.fc#L131-L167) + +#### Pyth Connector flow + +Pyth Connector's onchain-getter operation has a simplified flow compared to the EVAA protocol. + +```mermaid +sequenceDiagram + autonumber + participant U as User + participant JW as Jetton Wallet + participant M as Pyth Connector + participant P as Pyth Contract + + U->>JW: op transfer_jetton, forward_payload: (onchain_getter_operation) + note right of U: transfer jetton with forward payload + JW->>M: op transfer_notification, forward_payload: (onchain_getter_operation) + note right of JW: transfer notification with forward payload + M->>P: op 0x5 parse_price_feed_updates + update data + target feeds
+ payload(onchain_getter_operation) + P-->>M: op 0x5 parse_price_feed_updates(price feeds + prices)
+ payload(onchain_getter_operation) + note over P: Pyth Contract validates update data and
sends prices with payload to Pyth Connector contract + note over M: Pyth Connector validates sender
parses payload and
processes the transaction +``` + +- Related code (GitHub): + - [entry for jetton-transfer notification: pyth_connector.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/pyth_connector.fc#L109) + - [onchain_getter_operation request: pyth-connector.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/pyth_connector.fc#L126) + - [send request to the Pyth Contract: onchain_getter_operation.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/operations/onchain_getter_operation.fc#L71) + - [entry for the Pyth response: pyth-connector.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/pyth_connector.fc#L78) + - [onchain_getter_operation process: pyth-connector.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/pyth_connector.fc#L90) + +### Pyth onchain-getter: Pyth error + +Pyth sends an error response (`response_error`, op 0x10002) when it cannot process the price feed update request. This can happen if the request is malformed, contains invalid or outdated feed data, or if the requested feeds are unavailable. In such cases, the error response includes an error code and the original operation payload, allowing the original sender to handle the failure and refund the user if necessary. + +#### EVAA flow + +The error response is sent directly back to the user who initiated the transaction, not to a contract. This is different from the proxy case, where the error is returned to the EVAA Master contract for further handling and potential refund logic. In the onchain-getter case, the user receives the error response from the Pyth contract, including the error code and the original query ID, allowing the user to identify and handle the failure on their side. + +```mermaid +sequenceDiagram + autonumber + participant U as User + participant JW as Jetton Wallet + participant M as EVAA Master + participant P as Pyth Contract + + U->>JW: transfer with forward_payload + JW->>M: transfer_notification + M->>P: request (op 0x5 parse_price_feed_updates) + P-->>M: response_error (op 0x10002) + M-->>U: refund with error code +``` + +- Related code (GitHub): + - [entry point for the Pyth error message: master.fc (pyth_response_error)](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/master.fc#L92-L119) + - [refund the liquidate jetton operation: master-liquidate.fc](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/core/master-liquidate.fc#L753-L786) + - [refund the supply_withdraw_jetton operation: master-supply-withdrawal.fc](https://github.com/evaafi/contracts/blob/d9138cb24f03b53522774351aceb38c51a047eee/contracts/core/master-supply-withdrawal.fc#L899-L935) + +#### Pyth Connector + +The Pyth Connector error handling flow looks the same as the EVAA protocol. + +```mermaid +sequenceDiagram + autonumber + participant U as User + participant JW as Jetton Wallet + participant M as Pyth Connector + participant P as Pyth Contract + + U->>JW: transfer with forward_payload + JW->>M: transfer_notification + M->>P: request (op 0x5 parse_price_feed_updates) + P-->>M: response_error (op 0x10002) + M-->>U: refund with error code +``` + +- [entry point for the Pyth error message: pyth_connector.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/pyth_connector.fc#L31) +- [validate sender and detect onchain_getter_operation: pyth_connector.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/pyth_connector.fc#L32-L43) +- [handle the operation failure, refund jettons: onchain_getter_operation.fc](https://github.com/pyth-network/pyth-examples/blob/main/price_feeds/ton/pyth-connector/contracts/PythConnector/operations/onchain_getter_operation.fc#L21-L35) + +## Additional Resources + +You may find these additional resources helpful for developing your TON application: + +- [TON Documentation](https://ton.org/docs/) +- [Pyth Price Feed IDs](/price-feeds/core/price-feeds) +- [Pyth TON Contract](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ton/contracts) +- [Pyth TON SDK](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ton/sdk) +- [Pyth TON SDK Example](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/ton/sdk_js_usage) +- [Pyth TON Send USD Example](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/ton/send_usd) +- [Pyth Connector Example](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds/ton/pyth-connector) +- [EVAA Protocol Code](https://github.com/evaafi/contracts/tree/v8) + diff --git a/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/push-integration.mdx b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/push-integration.mdx new file mode 100644 index 0000000000..696eb24223 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/use-real-time-data/push-integration.mdx @@ -0,0 +1,76 @@ +--- +title: Push Integration +description: How to use Pyth push feeds across supported ecosystems +slug: /price-feeds/core/use-real-time-data/push-integration +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +This guide explains how to read real-time Pyth prices using push integration across supported ecosystems. + + + Ensure the feeds your application needs are already updated on-chain. Review + the [push feeds list](/price-feeds/core/push-feeds), request coverage through + the [update request form](https://tally.so/r/nGz2jj), or operate a [Price + Pusher](/price-feeds/core/schedule-price-updates/using-price-pusher) to + publish updates yourself. + + +## EVM + +Developers on EVM chains can read prices directly from the Pyth oracle contract using push feeds. + +```solidity copy +PythStructs.Price memory price = pyth.getPriceNoOlderThan(priceFeedId, 60); +``` + +Provide the price feed ID from the [push feeds list](/price-feeds/core/push-feeds). + +### Sample contract + +```solidity {30-31} copy +pragma solidity ^0.8.0; + +import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; +import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; + +contract SomeContract { + IPyth pyth; + + /** + * @param pythContract The address of the Pyth contract + */ + constructor(address pythContract) { + // The IPyth interface from pyth-sdk-solidity provides the methods to interact with the Pyth contract. + // Instantiate it with the Pyth contract address from https://docs.pyth.network/price-feeds/core/contract-addresses/evm + pyth = IPyth(pythContract); + } + + /** + * This method is an example of how to interact with the Pyth contract using Push Integration. + */ + function exampleMethod() public { + // Read the current price from a price feed if it is less than 60 seconds old. + // Each price feed (e.g., ETH/USD) is identified by a price feed ID. + // The complete list of feed IDs is available at https://docs.pyth.network/price-feeds/core/price-feeds + bytes32 priceFeedId = 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace; // ETH/USD + PythStructs.Price memory price = pyth.getPriceNoOlderThan(priceFeedId, 60); + } +} + +``` + +## SVM + +Developers on Solana and related ecosystems can use price feed accounts to consume push feeds. See the +[Solana integration guide](/price-feeds/core/use-real-time-data/pull-integration/solana#price-feed-accounts) for implementation details. + +## Aptos + +Developers on Aptos can read push feeds from the Pyth oracle contract: + +```rust copy +let btc_price_identifier = x"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; +let btc_usd_price_id = price_identifier::from_byte_vec(btc_price_identifier); +pyth::get_price(btc_usd_price_id) +``` diff --git a/apps/developer-hub/content/docs/price-feeds/core/why-update-prices.mdx b/apps/developer-hub/content/docs/price-feeds/core/why-update-prices.mdx new file mode 100644 index 0000000000..9999d437a6 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/core/why-update-prices.mdx @@ -0,0 +1,21 @@ +--- +title: Why Update Prices +description: Understand why Pyth pull-oracle integrations must refresh on-chain prices +slug: /price-feeds/core/why-update-prices +--- + +Pyth uses a pull oracle model. Unlike traditional push oracles that automatically update prices on-chain at regular intervals, Pyth requires users to explicitly update the on-chain price before reading it. + +This design offers several advantages: + +- **Lower costs**: You only pay for price updates when you need them +- **Lower latency**: You can fetch the latest price update directly from Pyth's low-latency oracle network and submit it on-chain immediately +- **Flexibility**: Different applications can update prices at different frequencies based on their needs + +In the pull integration pattern, your contract must: + +1. Accept `priceUpdate` data from the caller (fetched from [Hermes](./how-pyth-works/hermes)) +2. Call `updatePriceFeeds()` to submit this data on-chain before reading prices +3. Pay a small fee for each update (calculated via `getUpdateFee()`) + +If you don't update the price or if the on-chain price becomes too stale, calls to `getPriceNoOlderThan()` will revert with a `StalePrice` error. See [how to fetch price updates](./fetch-price-updates) for more details on obtaining price updates. diff --git a/apps/developer-hub/content/docs/price-feeds/index.mdx b/apps/developer-hub/content/docs/price-feeds/index.mdx index 716f783ccb..1d5c729de8 100644 --- a/apps/developer-hub/content/docs/price-feeds/index.mdx +++ b/apps/developer-hub/content/docs/price-feeds/index.mdx @@ -13,6 +13,7 @@ import { BookOpen, SquaresFour, } from "@phosphor-icons/react/dist/ssr"; +import styles from "./index.module.scss"; Pyth Price Feeds deliver real-time financial market data sources from 120+ first-party providers. These providers include leading exchanges, banks, trading firms, and market makers. Additionally, Pyth Price data can be verified on 100+ blockchains. @@ -20,7 +21,7 @@ Pyth Price Feeds deliver real-time financial market data sources from 120+ first Pyth offers two main versions of price feeds, each optimized for different use cases: -
+
} title="Price Feed IDs"> -

+

Complete price feed coverage for both Pyth Core and Pyth Pro.

-
- - Pyth Core IDs -> - - - Pyth Pro IDs -> - -
+ + Pyth Core IDs -> + + + Pyth Pro IDs -> +
} title="API Reference"> -

+

Explore REST and WebSocket APIs for Core and Pro integrations.

-
- - Core APIs -> - - - Pro APIs -> - -
+ + Core APIs -> + + + Pro APIs -> +
} title="Examples"> -

+

Review sample applications and integration workflows using Pyth data.

-
- - View examples -> - -
+ + View examples -> +
diff --git a/apps/developer-hub/content/docs/price-feeds/index.module.scss b/apps/developer-hub/content/docs/price-feeds/index.module.scss new file mode 100644 index 0000000000..9c4f6082cd --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/index.module.scss @@ -0,0 +1,11 @@ +@use "@pythnetwork/component-library/theme"; + +.productGrid { + display: grid; + gap: theme.spacing(6); + grid-template-columns: 1fr; + + @include theme.breakpoint("lg") { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} diff --git a/apps/developer-hub/content/docs/price-feeds/meta.json b/apps/developer-hub/content/docs/price-feeds/meta.json new file mode 100644 index 0000000000..ba34f05604 --- /dev/null +++ b/apps/developer-hub/content/docs/price-feeds/meta.json @@ -0,0 +1,8 @@ +{ + "root": true, + "title": "Price Feeds", + "description": "Real-time financial market data", + "pages": ["core", "pro"], + "defaultOpen": true, + "icon": "ChartLine" +} diff --git a/apps/developer-hub/migration-report.json b/apps/developer-hub/migration-report.json deleted file mode 100644 index fc21c8fd33..0000000000 --- a/apps/developer-hub/migration-report.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "source": "pages/price-feeds/core/use-real-time-data/pull-integration/cosmwasm.mdx", - "target": "content/docs/price-feeds/core/use-real-time-data/pull-integration/cosmwasm.mdx" - } -] diff --git a/apps/developer-hub/migration-report.md b/apps/developer-hub/migration-report.md deleted file mode 100644 index d81796d37a..0000000000 --- a/apps/developer-hub/migration-report.md +++ /dev/null @@ -1 +0,0 @@ -pages/price-feeds/core/use-real-time-data/pull-integration/cosmwasm.mdx -> content/docs/price-feeds/core/use-real-time-data/pull-integration/cosmwasm.mdx diff --git a/apps/developer-hub/package.json b/apps/developer-hub/package.json index d9c7961bd6..f762150b6d 100644 --- a/apps/developer-hub/package.json +++ b/apps/developer-hub/package.json @@ -25,6 +25,7 @@ "@pythnetwork/component-library": "workspace:*", "@pythnetwork/contract-manager": "workspace:*", "@pythnetwork/entropy-sdk-solidity": "workspace:*", + "@pythnetwork/pyth-solana-receiver": "workspace:*", "@react-hookz/web": "catalog:", "clsx": "catalog:", "fumadocs-core": "catalog:", @@ -35,6 +36,7 @@ "katex": "catalog:", "next": "catalog:", "next-themes": "catalog:", + "match-sorter": "catalog:", "@pythnetwork/react-hooks": "workspace:", "react": "catalog:", "react-aria": "catalog:", diff --git a/apps/developer-hub/public/images/Push-vs-Pull-Oracle.jpg b/apps/developer-hub/public/images/Push-vs-Pull-Oracle.jpg new file mode 100644 index 0000000000..45193c04e5 Binary files /dev/null and b/apps/developer-hub/public/images/Push-vs-Pull-Oracle.jpg differ diff --git a/apps/developer-hub/source.config.ts b/apps/developer-hub/source.config.ts index 816187d99c..e87acc69e3 100644 --- a/apps/developer-hub/source.config.ts +++ b/apps/developer-hub/source.config.ts @@ -1,4 +1,4 @@ -import { rehypeCode } from "fumadocs-core/mdx-plugins"; +import { remarkMdxMermaid, rehypeCode } from "fumadocs-core/mdx-plugins"; import { defineConfig, defineDocs } from "fumadocs-mdx/config"; import rehypeKatex from "rehype-katex"; import remarkMath from "remark-math"; @@ -48,6 +48,6 @@ export default defineConfig({ }, }, remarkPlugins: [remarkMath], - rehypePlugins: (v) => [rehypeKatex, rehypeCode, ...v], + rehypePlugins: (v) => [rehypeKatex, rehypeCode, remarkMdxMermaid, ...v], }, }); diff --git a/apps/developer-hub/src/components/Pages/Homepage/index.tsx b/apps/developer-hub/src/components/Pages/Homepage/index.tsx index 99c687c2f0..fa7ac8f2e6 100644 --- a/apps/developer-hub/src/components/Pages/Homepage/index.tsx +++ b/apps/developer-hub/src/components/Pages/Homepage/index.tsx @@ -26,16 +26,16 @@ export const Homepage = () => { quickLinks={[ { label: "Getting Started", - href: "/price-feeds/v1/getting-started", + href: "/price-feeds/core", }, - { label: "API Reference", href: "/openapi/hermes" }, + { label: "API Reference", href: "/price-feeds/core/api-reference" }, { label: "Contract Addresses", - href: "/price-feeds/v1/contract-addresses", + href: "/price-feeds/core/contract-addresses", }, ]} buttonLabel="Get started" - buttonHref="/price-feeds/v1" + buttonHref="/price-feeds/core" /> { quickLinks={[ { label: "Get Pyth Pro Access Token", - href: "/price-feeds/v2/acquire-an-access-token", + href: "/price-feeds/pro/access-token", }, - { label: "Browse Supported Feeds", href: "/price-feeds" }, - { label: "Error Codes", href: "/price-feeds" }, + { + label: "Browse Supported Feeds", + href: "/price-feeds/pro/price-feeds", + }, + { label: "Error Codes", href: "/price-feeds/pro/error-codes" }, ]} buttonLabel="Get started" - buttonHref="/price-feeds" + buttonHref="/price-feeds/pro" /> { + const [state, setState] = useState(State.NotLoaded()); + useEffect(() => { + setState(State.Loading()); + getFeeds() + .then((feeds) => { + setState(State.Loaded(feeds)); + }) + .catch((error: unknown) => { + setState(State.Failed(error)); + }); + }, []); + + const columns: ColumnConfig[] = [ + { id: "symbol", name: "Symbol", isRowHeader: true }, + { id: "stableFeedId", name: "Stable Price Feed ID" }, + { id: "betaFeedId", name: "Beta Price Feed ID" }, + { id: "solanaPriceFeedAccount", name: "Solana Price Feed Account" }, + ]; + + const { + search, + sortDescriptor, + page, + pageSize, + updateSearch, + updateSortDescriptor, + updatePage, + updatePageSize, + paginatedItems, + numPages, + mkPageLink, + } = useQueryParamFilterPagination( + state.type === StateType.Loaded ? state.feeds : [], + () => true, + () => 1, + (items, searchString) => { + return matchSorter(items, searchString, { + keys: [ + "symbol", + "stableFeedId", + "betaFeedId", + "solanaPriceFeedAccount", + ], + }); + }, + { defaultSort: "symbol", defaultPageSize: 10 }, + ); + + if (state.type === StateType.Error) { + return {errorToString(state.error)}; + } + + const isLoading = + state.type === StateType.Loading || state.type === StateType.NotLoaded; + + const rows = paginatedItems.map((feed) => ({ + id: feed.symbol, + data: { + symbol: feed.symbol, + stableFeedId: feed.stableFeedId ? ( + + ) : undefined, + betaFeedId: feed.betaFeedId ? ( + + ) : undefined, + solanaPriceFeedAccount: feed.solanaPriceFeedAccount ? ( + + ) : undefined, + }, + })); + + return ( + <> + + + + {...(isLoading ? { isLoading: true } : { isLoading: false, rows })} + label="Price feed ids" + columns={columns} + onSortChange={updateSortDescriptor} + sortDescriptor={sortDescriptor} + stickyHeader="top" + fill + rounded + /> + + + ); +}; + +const errorToString = (error: unknown) => { + if (error instanceof Error) { + return error.message; + } else if (typeof error === "string") { + return error; + } else { + return "An error occurred, please try again"; + } +}; + +enum StateType { + NotLoaded, + Loading, + Loaded, + Error, +} + +const State = { + NotLoaded: () => ({ type: StateType.NotLoaded as const }), + Loading: () => ({ type: StateType.Loading as const }), + Loaded: (feeds: Awaited>) => ({ + type: StateType.Loaded as const, + feeds, + }), + Failed: (error: unknown) => ({ type: StateType.Error as const, error }), +}; +type State = ReturnType<(typeof State)[keyof typeof State]>; + +const getFeeds = async () => { + const [pythnet, pythtest] = await Promise.all([ + getFeedsFromHermes("https://hermes.pyth.network"), + getFeedsFromHermes("https://hermes-beta.pyth.network"), + ]); + + const feeds = new Map< + string, + { + stableFeedId?: string; + betaFeedId?: string; + solanaPriceFeedAccount?: string; + } + >(); + + for (const feed of pythnet) { + feeds.set(feed.attributes.symbol, { + stableFeedId: `0x${feed.id}`, + solanaPriceFeedAccount: getPriceFeedAccountForProgram( + 0, + Buffer.from(feed.id, "hex"), + ).toBase58(), + }); + } + for (const feed of pythtest) { + feeds.set(feed.attributes.symbol, { + ...feeds.get(feed.attributes.symbol), + betaFeedId: `0x${feed.id}`, + }); + } + + return [...feeds.entries()] + .toSorted((a, b) => a[0].localeCompare(b[0])) + .map(([symbol, attrs]) => ({ symbol, ...attrs })); +}; + +const getFeedsFromHermes = async (hermesUrl: string) => { + const result = await fetch(new URL("/v2/price_feeds", hermesUrl)); + return hermesSchema.parse(await result.json()); +}; + +const hermesSchema = z.array( + z.object({ + id: z.string(), + attributes: z.object({ symbol: z.string() }), + }), +); + +type Col = "symbol" | "stableFeedId" | "betaFeedId" | "solanaPriceFeedAccount"; diff --git a/apps/developer-hub/src/components/Root/global.css b/apps/developer-hub/src/components/Root/global.css index 21df71c9b0..7af62f670a 100644 --- a/apps/developer-hub/src/components/Root/global.css +++ b/apps/developer-hub/src/components/Root/global.css @@ -1,3 +1,24 @@ +.image-container { + display: flex; + justify-content: center; + border: 1px solid var(--color-gray-200, #e5e7eb); + background-color: var(--color-gray-50, #f9fafb); + border-radius: 12px; + padding: 24px; + margin: 24px 0; +} + +.image-container img { + max-width: 100%; + height: auto; +} + +@media (prefers-color-scheme: dark) { + .image-container { + border-color: var(--color-gray-800, #1f2937); + background-color: var(--color-gray-900, #111827); + } +} @import "tailwindcss"; @import "fumadocs-ui/css/neutral.css"; @import "fumadocs-ui/css/preset.css"; diff --git a/apps/developer-hub/src/components/SponsoredFeedsTable/index.module.scss b/apps/developer-hub/src/components/SponsoredFeedsTable/index.module.scss new file mode 100644 index 0000000000..0c0aa723eb --- /dev/null +++ b/apps/developer-hub/src/components/SponsoredFeedsTable/index.module.scss @@ -0,0 +1,217 @@ +.container { + margin: 1.5rem 0; +} + +.introText { + margin-bottom: 1rem; + color: var(--color-gray-700); + font-size: 1rem; +} + +.tableWrapper { + border: 1px solid var(--color-gray-200); + border-radius: 0.75rem; + background-color: var(--color-white); + box-shadow: 0 1px 2px rgb(15 23 42 / 8%); + overflow: hidden; +} + +.summaryBar { + display: flex; + flex-wrap: wrap; + gap: 1.25rem; + padding: 0.75rem 1rem; + background-color: var(--color-blue-50); + border-bottom: 1px solid var(--color-gray-200); +} + +.summaryItem { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--color-gray-700); + font-size: 0.875rem; +} + +.summaryLabel { + font-weight: 600; +} + +.summaryCount { + color: var(--color-gray-500); +} + +.statusDot { + width: 0.5rem; + height: 0.5rem; + border-radius: 9999px; + background-color: var(--color-gray-400); + flex-shrink: 0; +} + +.statusDotDefault { + background-color: var(--color-green-500); +} + +.statusDotException { + background-color: var(--color-orange-500); +} + +.tableScroll { + max-height: 24rem; + overflow: auto; +} + +.table { + width: 100%; + border-collapse: collapse; + font-size: 0.875rem; + min-width: 620px; +} + +.tableHead { + position: sticky; + top: 0; + background-color: var(--color-gray-50); + border-bottom: 1px solid var(--color-gray-200); + z-index: 2; +} + +.headerCell { + padding: 0.75rem 0.875rem; + text-align: left; + font-weight: 600; + color: var(--color-gray-900); + border-bottom: 1px solid var(--color-gray-200); +} + +.tableBody { + background-color: var(--color-white); +} + +.tableRow { + border-bottom: 1px solid var(--color-gray-100); + transition: background-color 0.2s ease; +} + +.tableRow:hover { + background-color: var(--color-gray-50); +} + +.nameCell, +.accountCell, +.idCell, +.paramsCell { + padding: 0.75rem 0.875rem; + vertical-align: top; + color: var(--color-gray-800); +} + +.nameLabel { + font-weight: 600; + color: var(--color-gray-900); +} + +.copyWrapper { + display: inline-flex; + align-items: flex-start; + gap: 0.5rem; +} + +.code { + font-family: var(--py-font-family-mono, "IBM Plex Mono", monospace); + font-size: 0.75rem; + line-height: 1.4; + color: var(--color-gray-600); + word-break: break-all; +} + +.updateParams { + display: flex; + align-items: flex-start; + gap: 0.5rem; +} + +.updateParamsText { + font-size: 0.75rem; + line-height: 1.5; + color: var(--color-gray-700); +} + +.updateParamsDefault .updateParamsText { + color: var(--color-gray-700); +} + +.updateParamsException .updateParamsText { + color: var(--color-orange-600); +} + +@media (prefers-color-scheme: dark) { + .introText { + color: var(--color-gray-300); + } + + .tableWrapper { + border-color: var(--color-gray-700); + background-color: var(--color-gray-900); + box-shadow: none; + } + + .summaryBar { + background-color: rgb(30 64 175 / 25%); + border-color: var(--color-gray-700); + } + + .summaryItem { + color: var(--color-gray-300); + } + + .summaryCount { + color: var(--color-gray-500); + } + + .tableHead { + background-color: var(--color-gray-800); + border-color: var(--color-gray-700); + } + + .headerCell { + color: var(--color-gray-100); + border-color: var(--color-gray-700); + } + + .tableBody { + background-color: var(--color-gray-900); + } + + .tableRow { + border-color: rgb(148 163 184 / 15%); + } + + .tableRow:hover { + background-color: rgb(148 163 184 / 10%); + } + + .nameCell, + .accountCell, + .idCell, + .paramsCell { + color: var(--color-gray-200); + } + + .nameLabel { + color: var(--color-gray-100); + } + + .code { + color: var(--color-gray-400); + } + + .updateParamsText { + color: var(--color-gray-300); + } + + .updateParamsException .updateParamsText { + color: var(--color-orange-400); + } +} diff --git a/apps/developer-hub/src/components/SponsoredFeedsTable/index.tsx b/apps/developer-hub/src/components/SponsoredFeedsTable/index.tsx new file mode 100644 index 0000000000..b04636f04e --- /dev/null +++ b/apps/developer-hub/src/components/SponsoredFeedsTable/index.tsx @@ -0,0 +1,193 @@ +import { CopyButton } from "@pythnetwork/component-library/CopyButton"; +import clsx from "clsx"; + +import styles from "./index.module.scss"; + +type SponsoredFeed = { + alias: string; + account_address?: string; + id: string; + time_difference: number; + price_deviation: number; + confidence_ratio: number; +}; + +type SponsoredFeedsTableProps = { + feeds: SponsoredFeed[]; + networkName: string; +}; + +type UpdateParamsProps = { + feed: SponsoredFeed; + isDefault: boolean; +}; + +const formatTimeDifference = ( + seconds: number, +): { value: number; unit: string } => { + if (seconds >= 3600) { + const hours = Math.floor(seconds / 3600); + return { value: hours, unit: hours === 1 ? "hour" : "hours" }; + } + + if (seconds >= 60) { + const minutes = Math.floor(seconds / 60); + return { value: minutes, unit: minutes === 1 ? "minute" : "minutes" }; + } + + return { value: seconds, unit: seconds === 1 ? "second" : "seconds" }; +}; + +const formatUpdateParams = (feed: SponsoredFeed): string => { + const timeFormat = formatTimeDifference(feed.time_difference); + const timeLabel = `${timeFormat.value.toString()} ${timeFormat.unit}`; + return `${timeLabel} heartbeat / ${feed.price_deviation.toString()}% price deviation`; +}; + +const UpdateParams = ({ feed, isDefault }: UpdateParamsProps) => { + const timeFormat = formatTimeDifference(feed.time_difference); + const timeLabel = + timeFormat.value === 1 + ? timeFormat.unit.replace(/s$/, "") + : `${timeFormat.unit.replace(/s$/, "")}s`; + + return ( +
+
+ + {timeFormat.value} {timeLabel} heartbeat +
+ {feed.price_deviation}% price deviation +
+
+ ); +}; + +export const SponsoredFeedsTable = ({ + feeds, + networkName, +}: SponsoredFeedsTableProps) => { + if (feeds.length === 0) { + return ( +
+

+ No sponsored price feeds are currently available for{" "} + {networkName}. +

+
+ ); + } + + const paramCounts: Record = {}; + for (const feed of feeds) { + const key = formatUpdateParams(feed); + const current = paramCounts[key] ?? 0; + paramCounts[key] = current + 1; + } + + const paramEntries = Object.entries(paramCounts).sort( + (entryA, entryB) => entryB[1] - entryA[1], + ); + const defaultParams = paramEntries[0]?.[0]; + const defaultCount = + defaultParams === undefined ? 0 : (paramCounts[defaultParams] ?? 0); + + const hasAccountAddress = feeds.some((feed) => !!feed.account_address); + + return ( +
+

+ The price feeds listed below are currently sponsored in{" "} + {networkName}. +

+
+
+ {defaultParams ? ( +
+ + Default: + {defaultParams} + ({defaultCount}) +
+ ) : undefined} + {paramEntries + .filter(([params]) => params !== defaultParams) + .map(([params, count]) => ( +
+ + Exception: + {params} + ({count}) +
+ ))} +
+ +
+ + + + + {hasAccountAddress ? ( + + ) : undefined} + + + + + + {feeds.map((feed) => { + const formattedParams = formatUpdateParams(feed); + const isDefault = formattedParams === defaultParams; + + return ( + + + {hasAccountAddress ? ( + + ) : undefined} + + + + ); + })} + +
NameAccount AddressPrice Feed IdUpdate Parameters
+ {feed.alias} + + {feed.account_address ? ( +
+ + {feed.account_address} + + +
+ ) : undefined} +
+
+ {feed.id} + +
+
+ +
+
+
+
+ ); +}; + +export default SponsoredFeedsTable; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3ec1425a1..26fc9caa48 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -521,6 +521,9 @@ importers: '@pythnetwork/entropy-sdk-solidity': specifier: workspace:* version: link:../../target_chains/ethereum/entropy_sdk/solidity + '@pythnetwork/pyth-solana-receiver': + specifier: workspace:* + version: link:../../target_chains/solana/sdk/js/pyth_solana_receiver '@pythnetwork/react-hooks': specifier: 'workspace:' version: link:../../packages/react-hooks @@ -548,6 +551,9 @@ importers: katex: specifier: 'catalog:' version: 0.16.22 + match-sorter: + specifier: 'catalog:' + version: 8.1.0 next: specifier: 'catalog:' version: 15.5.0(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.1.0-rc.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1)