From 0928e433aa6ed234d04374b67d3b27c11efd7c12 Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Mon, 23 Jun 2025 13:49:00 -0400 Subject: [PATCH 1/3] chore(pricefeed) Add docs for cross rate --- pages/price-feeds/_meta.json | 1 + pages/price-feeds/combine-two-price-feeds.mdx | 101 ++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 pages/price-feeds/combine-two-price-feeds.mdx diff --git a/pages/price-feeds/_meta.json b/pages/price-feeds/_meta.json index 8c2d4ea1..62747325 100644 --- a/pages/price-feeds/_meta.json +++ b/pages/price-feeds/_meta.json @@ -26,6 +26,7 @@ "use-real-time-data": "Use Real-Time Price Data", "fetch-price-updates": "Fetch Price Updates", "schedule-price-updates": "Schedule Price Updates", + "combine-two-price-feeds": "Combine Two Price Feeds / Derive a Cross Rate", "migrate-an-app-to-pyth": "Migrate an App to Pyth", "use-pyth-for-morpho": "Use Pyth for Morpho Markets", "publish-data": "Publish Data", diff --git a/pages/price-feeds/combine-two-price-feeds.mdx b/pages/price-feeds/combine-two-price-feeds.mdx new file mode 100644 index 00000000..f84673c3 --- /dev/null +++ b/pages/price-feeds/combine-two-price-feeds.mdx @@ -0,0 +1,101 @@ +import { Callout } from "nextra/components"; + +# Combine Two Price Feeds / Derive a Cross Rate + +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. + + + This guide is for developers who are building applications on **EVM + blockchains** using **solidity only**. + + +## Example + +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}`**. + +$$ +\large{\text{ETH/EUR} = \text{ETH/USD} \div \text{EUR/USD}} +$$ + +## Derive a cross rate + +Pyth 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. +This method is available in [Pyth solidity SDK](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ethereum/sdk/solidity). + +This method takes the following parameters: + +- `price1`: The first price feed value, representing a / b (e.g., ETH/USD). Must be a signed integer (int64). +- `expo1`: The exponent for price1, indicating the number of decimal places. +- `price2`: The second price feed value, representing c / b (e.g., EUR/USD). +- `expo2`: The exponent for price2. +- `targetExponent`: The desired exponent for the output cross rate (a / c). The result will be scaled to this exponent. + +Returns: + +- `crossRate`: The computed cross rate (a / c), scaled to targetExponent. + +### ⚠️ Things to Keep in Mind + +- The function reverts if either price is **negative**, or if any exponent is **less than -255**. +- The result is rounded down. If the result is smaller than 1 in the given `targetExponent{:jsx}`, it will return 0. +- Confidence intervals are not derived in this function. If needed, you have to derive them manually. +- Reverts with `PythErrors.ExponentOverflow{:jsx}` if `targetExponent + expo1 - expo2{:jsx}` is outside the range **[-58, 58]**. + +## Example + +```solidity copy +pragma solidity ^0.8.0; + +import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; +import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; +import "@pythnetwork/pyth-sdk-solidity/PythUtils.sol"; + +contract ExampleCrossRate { + IPyth public pyth; + + constructor(address _pythContract) { + pyth = IPyth(_pythContract); + } + + // priceUpdate should include both price feeds + function getEthPerEur( + bytes32 ethUsdId, + bytes32 eurUsdId, + bytes[] calldata priceUpdate + ) external payable returns (int64 price, int32 expo) { + // Update both feeds + uint fee = pyth.getUpdateFee(priceUpdate); + pyth.updatePriceFeeds{ value: fee }(priceUpdate); + + // Fetch prices + PythStructs.Price memory ethUsd = pyth.getPriceNoOlderThan(ethUsdId, 60); + PythStructs.Price memory eurUsd = pyth.getPriceNoOlderThan(eurUsdId, 60); + + // Derive ETH/EUR = ETH/USD ÷ EUR/USD + int32 targetExpo = -8; + int64 ethPerEur = PythUtils.deriveCrossRate( + ethUsd.price, + ethUsd.expo, + eurUsd.price, + eurUsd.expo, + targetExpo + ); + + return (ethPerEur, targetExpo); + } +} + +``` + +## Additional Resources + +You may find these additional resources helpful. + +### How to use real-time data in EVM contracts + +The [How to use real-time data in EVM contracts](./use-real-time-data/evm) guide provides a step-by-step guide on how to use real-time data in EVM contracts. + +### Price Feed IDs + +The [Price Feed IDs](https://www.pyth.network/developers/price-feed-ids) page lists the price feed IDs for each asset supported by Pyth. From 45062457bc93ba67c90818ffa847d2734fc835e2 Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Mon, 23 Jun 2025 14:11:52 -0400 Subject: [PATCH 2/3] requested updates --- pages/price-feeds/_meta.json | 2 +- ...-price-feeds.mdx => derive-cross-rate.mdx} | 23 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) rename pages/price-feeds/{combine-two-price-feeds.mdx => derive-cross-rate.mdx} (92%) diff --git a/pages/price-feeds/_meta.json b/pages/price-feeds/_meta.json index 62747325..218fcfc5 100644 --- a/pages/price-feeds/_meta.json +++ b/pages/price-feeds/_meta.json @@ -26,7 +26,7 @@ "use-real-time-data": "Use Real-Time Price Data", "fetch-price-updates": "Fetch Price Updates", "schedule-price-updates": "Schedule Price Updates", - "combine-two-price-feeds": "Combine Two Price Feeds / Derive a Cross Rate", + "derive-cross-rate": "Derive Cross Rate", "migrate-an-app-to-pyth": "Migrate an App to Pyth", "use-pyth-for-morpho": "Use Pyth for Morpho Markets", "publish-data": "Publish Data", diff --git a/pages/price-feeds/combine-two-price-feeds.mdx b/pages/price-feeds/derive-cross-rate.mdx similarity index 92% rename from pages/price-feeds/combine-two-price-feeds.mdx rename to pages/price-feeds/derive-cross-rate.mdx index f84673c3..5e56872a 100644 --- a/pages/price-feeds/combine-two-price-feeds.mdx +++ b/pages/price-feeds/derive-cross-rate.mdx @@ -1,6 +1,6 @@ import { Callout } from "nextra/components"; -# Combine Two Price Feeds / Derive a Cross Rate +# Derive Cross Rate 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. @@ -20,7 +20,7 @@ $$ ## Derive a cross rate -Pyth 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. +The Pyth Solidity SDKprovides [`deriveCrossRate`](https://github.com/pyth-network/pyth-crosschain/blob/main/target_chains/ethereum/sdk/solidity/PythUtils.sol#L77) function to combine two price feeds. This method is available in [Pyth solidity SDK](https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ethereum/sdk/solidity). This method takes the following parameters: @@ -35,13 +35,6 @@ Returns: - `crossRate`: The computed cross rate (a / c), scaled to targetExponent. -### ⚠️ Things to Keep in Mind - -- The function reverts if either price is **negative**, or if any exponent is **less than -255**. -- The result is rounded down. If the result is smaller than 1 in the given `targetExponent{:jsx}`, it will return 0. -- Confidence intervals are not derived in this function. If needed, you have to derive them manually. -- Reverts with `PythErrors.ExponentOverflow{:jsx}` if `targetExponent + expo1 - expo2{:jsx}` is outside the range **[-58, 58]**. - ## Example ```solidity copy @@ -72,7 +65,7 @@ contract ExampleCrossRate { PythStructs.Price memory ethUsd = pyth.getPriceNoOlderThan(ethUsdId, 60); PythStructs.Price memory eurUsd = pyth.getPriceNoOlderThan(eurUsdId, 60); - // Derive ETH/EUR = ETH/USD ÷ EUR/USD + // Derive ETH/EUR = ETH/USD / EUR/USD int32 targetExpo = -8; int64 ethPerEur = PythUtils.deriveCrossRate( ethUsd.price, @@ -85,9 +78,17 @@ contract ExampleCrossRate { return (ethPerEur, targetExpo); } } - ``` + +### ⚠️ Things to Keep in Mind + +- The function reverts if either price is **negative**, or if any exponent is **less than -255**. +- The result is rounded down. If the result is smaller than 1 in the given `targetExponent{:jsx}`, it will return 0. +- Confidence intervals are not derived in this function. If needed, you have to derive them manually. +- Reverts with `PythErrors.ExponentOverflow{:jsx}` if `targetExponent + expo1 - expo2{:jsx}` is outside the range **[-58, 58]**. + + ## Additional Resources You may find these additional resources helpful. From 0ba334a2c5bfe15ec114ba5b2778d3eda484a209 Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Mon, 23 Jun 2025 14:12:54 -0400 Subject: [PATCH 3/3] pre-commit --- pages/price-feeds/derive-cross-rate.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/price-feeds/derive-cross-rate.mdx b/pages/price-feeds/derive-cross-rate.mdx index 5e56872a..0a6feaff 100644 --- a/pages/price-feeds/derive-cross-rate.mdx +++ b/pages/price-feeds/derive-cross-rate.mdx @@ -78,8 +78,8 @@ contract ExampleCrossRate { return (ethPerEur, targetExpo); } } -``` +``` ### ⚠️ Things to Keep in Mind @@ -88,7 +88,6 @@ contract ExampleCrossRate { - Confidence intervals are not derived in this function. If needed, you have to derive them manually. - Reverts with `PythErrors.ExponentOverflow{:jsx}` if `targetExponent + expo1 - expo2{:jsx}` is outside the range **[-58, 58]**. - ## Additional Resources You may find these additional resources helpful.