diff --git a/src/telliot_feeds/constants.py b/src/telliot_feeds/constants.py index 7c3c168b..10f7b968 100644 --- a/src/telliot_feeds/constants.py +++ b/src/telliot_feeds/constants.py @@ -25,6 +25,7 @@ 84532, 111, 60808, + 919, } GNOSIS_CHAINS = {100, 10200} diff --git a/src/telliot_feeds/feeds/__init__.py b/src/telliot_feeds/feeds/__init__.py index 4d6bf63b..d2887759 100644 --- a/src/telliot_feeds/feeds/__init__.py +++ b/src/telliot_feeds/feeds/__init__.py @@ -40,6 +40,7 @@ from telliot_feeds.feeds.evm_balance_current import evm_balance_current_feed_example from telliot_feeds.feeds.evm_call_feed import evm_call_feed from telliot_feeds.feeds.evm_call_feed import evm_call_feed_example +from telliot_feeds.feeds.ezeth_usd_feed import ezeth_usd_median_feed from telliot_feeds.feeds.fil_usd_feed import fil_usd_median_feed from telliot_feeds.feeds.fileCID_manual_feed import fileCID_manual_feed from telliot_feeds.feeds.frax_usd_feed import frax_usd_median_feed @@ -68,6 +69,7 @@ from telliot_feeds.feeds.mimicry.nft_index_feed import mimicry_nft_market_index_usd_feed from telliot_feeds.feeds.mkr_usd_feed import mkr_usd_median_feed from telliot_feeds.feeds.mnt_usd_feed import mnt_usd_median_feed +from telliot_feeds.feeds.mode_usd_feed import mode_usd_median_feed from telliot_feeds.feeds.numeric_api_response_feed import numeric_api_response_feed from telliot_feeds.feeds.numeric_api_response_manual_feed import numeric_api_response_manual_feed from telliot_feeds.feeds.oeth_eth_feed import oeth_eth_median_feed @@ -83,6 +85,7 @@ from telliot_feeds.feeds.reth_btc_feed import reth_btc_median_feed from telliot_feeds.feeds.reth_usd_feed import reth_usd_median_feed from telliot_feeds.feeds.ric_usd_feed import ric_usd_median_feed +from telliot_feeds.feeds.rseth_usd_feed import rseth_usd_median_feed from telliot_feeds.feeds.sdai_usd_feed import sdai_usd_median_feed from telliot_feeds.feeds.sfrax_usd_feed import sfrax_usd_feed from telliot_feeds.feeds.shib_usd_feed import shib_usd_median_feed @@ -108,8 +111,10 @@ from telliot_feeds.feeds.vesq import vsq_usd_median_feed from telliot_feeds.feeds.wbeth_usd_feed import wbeth_usd_median_feed from telliot_feeds.feeds.wbtc_usd_feed import wbtc_usd_median_feed +from telliot_feeds.feeds.weeth_usd_feed import weeth_usd_median_feed from telliot_feeds.feeds.wld_usd_feed import wld_usd_median_feed from telliot_feeds.feeds.wmnt_usd_feed import wmnt_usd_median_feed +from telliot_feeds.feeds.wrseth_usd_feed import wrseth_usd_feed from telliot_feeds.feeds.wsteth_feed import wsteth_eth_median_feed from telliot_feeds.feeds.wsteth_feed import wsteth_usd_median_feed from telliot_feeds.feeds.wusdm_usd_feed import wusdm_usd_feed @@ -212,6 +217,11 @@ "gyd-usd-spot": gyd_usd_median_feed, "leth-usd-spot": leth_usd_feed, "frxeth-usd-spot": frxeth_usd_median_feed, + "ezeth-usd-spot": ezeth_usd_median_feed, + "weeth-usd-spot": weeth_usd_median_feed, + "wrseth-usd-spot": wrseth_usd_feed, + "mode-usd-spot": mode_usd_median_feed, + "rseth-usd-spot": rseth_usd_median_feed, } DATAFEED_BUILDER_MAPPING: Dict[str, DataFeed[Any]] = { diff --git a/src/telliot_feeds/feeds/ezeth_usd_feed.py b/src/telliot_feeds/feeds/ezeth_usd_feed.py new file mode 100644 index 00000000..decc5605 --- /dev/null +++ b/src/telliot_feeds/feeds/ezeth_usd_feed.py @@ -0,0 +1,23 @@ +from telliot_feeds.datafeed import DataFeed +from telliot_feeds.queries.price.spot_price import SpotPrice +from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource +from telliot_feeds.sources.price.spot.coinpaprika import CoinpaprikaSpotPriceSource +from telliot_feeds.sources.price.spot.curvefiprice import CurveFiUSDPriceSource +from telliot_feeds.sources.price.spot.uniswapV3 import UniswapV3PriceSource +from telliot_feeds.sources.price_aggregator import PriceAggregator + + +ezeth_usd_median_feed = DataFeed( + query=SpotPrice(asset="EZETH", currency="USD"), + source=PriceAggregator( + asset="ezeth", + currency="usd", + algorithm="median", + sources=[ + CoinGeckoSpotPriceSource(asset="ezeth", currency="usd"), + CurveFiUSDPriceSource(asset="ezeth", currency="usd"), + CoinpaprikaSpotPriceSource(asset="ezeth-renzo-restaked-eth", currency="usd"), + UniswapV3PriceSource(asset="ezeth", currency="usd"), + ], + ), +) diff --git a/src/telliot_feeds/feeds/mode_usd_feed.py b/src/telliot_feeds/feeds/mode_usd_feed.py new file mode 100644 index 00000000..450d9ab2 --- /dev/null +++ b/src/telliot_feeds/feeds/mode_usd_feed.py @@ -0,0 +1,20 @@ +from telliot_feeds.datafeed import DataFeed +from telliot_feeds.queries.price.spot_price import SpotPrice +from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource +from telliot_feeds.sources.price.spot.coinpaprika import CoinpaprikaSpotPriceSource +from telliot_feeds.sources.price.spot.kimexchange import kimexchangePriceSource +from telliot_feeds.sources.price_aggregator import PriceAggregator + +mode_usd_median_feed = DataFeed( + query=SpotPrice(asset="MODE", currency="USD"), + source=PriceAggregator( + asset="mode", + currency="usd", + algorithm="median", + sources=[ + CoinGeckoSpotPriceSource(asset="mode", currency="usd"), + CoinpaprikaSpotPriceSource(asset="mode-mode", currency="usd"), + kimexchangePriceSource(asset="mode", currency="usd"), + ], + ), +) diff --git a/src/telliot_feeds/feeds/rseth_usd_feed.py b/src/telliot_feeds/feeds/rseth_usd_feed.py new file mode 100644 index 00000000..906e2d45 --- /dev/null +++ b/src/telliot_feeds/feeds/rseth_usd_feed.py @@ -0,0 +1,23 @@ +from telliot_feeds.datafeed import DataFeed +from telliot_feeds.queries.price.spot_price import SpotPrice +from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource +from telliot_feeds.sources.price.spot.coinpaprika import CoinpaprikaSpotPriceSource +from telliot_feeds.sources.price.spot.curvefiprice import CurveFiUSDPriceSource +from telliot_feeds.sources.price.spot.uniswapV3 import UniswapV3PriceSource +from telliot_feeds.sources.price_aggregator import PriceAggregator + + +rseth_usd_median_feed = DataFeed( + query=SpotPrice(asset="rsETH", currency="USD"), + source=PriceAggregator( + asset="rseth", + currency="usd", + algorithm="median", + sources=[ + CoinGeckoSpotPriceSource(asset="rseth", currency="usd"), + CurveFiUSDPriceSource(asset="rseth", currency="usd"), + CoinpaprikaSpotPriceSource(asset="rseth-rseth", currency="usd"), + UniswapV3PriceSource(asset="rseth", currency="usd"), + ], + ), +) diff --git a/src/telliot_feeds/feeds/weeth_usd_feed.py b/src/telliot_feeds/feeds/weeth_usd_feed.py new file mode 100644 index 00000000..c3659908 --- /dev/null +++ b/src/telliot_feeds/feeds/weeth_usd_feed.py @@ -0,0 +1,23 @@ +from telliot_feeds.datafeed import DataFeed +from telliot_feeds.queries.price.spot_price import SpotPrice +from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource +from telliot_feeds.sources.price.spot.coinpaprika import CoinpaprikaSpotPriceSource +from telliot_feeds.sources.price.spot.curvefiprice import CurveFiUSDPriceSource +from telliot_feeds.sources.price.spot.uniswapV3 import UniswapV3PriceSource +from telliot_feeds.sources.price_aggregator import PriceAggregator + + +weeth_usd_median_feed = DataFeed( + query=SpotPrice(asset="WEETH", currency="USD"), + source=PriceAggregator( + asset="weeth", + currency="usd", + algorithm="median", + sources=[ + CoinGeckoSpotPriceSource(asset="weeth", currency="usd"), + CurveFiUSDPriceSource(asset="weeth", currency="usd"), + CoinpaprikaSpotPriceSource(asset="weeth-wrapped-eeth", currency="usd"), + UniswapV3PriceSource(asset="weeth", currency="usd"), + ], + ), +) diff --git a/src/telliot_feeds/feeds/wrseth_usd_feed.py b/src/telliot_feeds/feeds/wrseth_usd_feed.py new file mode 100644 index 00000000..56df580a --- /dev/null +++ b/src/telliot_feeds/feeds/wrseth_usd_feed.py @@ -0,0 +1,8 @@ +from telliot_feeds.datafeed import DataFeed +from telliot_feeds.queries.price.spot_price import SpotPrice +from telliot_feeds.sources.wrseth_source import wrsETHSpotPriceSource + + +wrseth_usd_feed = DataFeed( + query=SpotPrice(asset="WRSETH", currency="USD"), source=wrsETHSpotPriceSource(asset="wrseth", currency="usd") +) diff --git a/src/telliot_feeds/queries/price/spot_price.py b/src/telliot_feeds/queries/price/spot_price.py index a63655dc..9bd3a355 100644 --- a/src/telliot_feeds/queries/price/spot_price.py +++ b/src/telliot_feeds/queries/price/spot_price.py @@ -89,6 +89,11 @@ "LETH/USD", "FRXETH/USD", "SFUEL/USD", + "EZETH/USD", + "WEETH/USD", + "WRSETH/USD", + "MODE/USD", + "RSETH/USD", ] diff --git a/src/telliot_feeds/queries/query_catalog.py b/src/telliot_feeds/queries/query_catalog.py index 2c6a79ca..eb4158af 100644 --- a/src/telliot_feeds/queries/query_catalog.py +++ b/src/telliot_feeds/queries/query_catalog.py @@ -602,3 +602,33 @@ title="FileCID query example", q=FileCIDQuery(url="https://raw.githubusercontent.com/tellor-io/dataSpecs/main/README.md"), ) + +query_catalog.add_entry( + tag="ezeth-usd-spot", + title="EZETH/USD spot price", + q=SpotPrice(asset="ezeth", currency="usd"), +) + +query_catalog.add_entry( + tag="weeth-usd-spot", + title="WEETH/USD spot price", + q=SpotPrice(asset="weeth", currency="usd"), +) + +query_catalog.add_entry( + tag="wrseth-usd-spot", + title="WRSETH/USD spot price", + q=SpotPrice(asset="wrseth", currency="usd"), +) + +query_catalog.add_entry( + tag="rseth-usd-spot", + title="RSETH/USD spot price", + q=SpotPrice(asset="rseth", currency="usd"), +) + +query_catalog.add_entry( + tag="mode-usd-spot", + title="MODE/USD spot price", + q=SpotPrice(asset="mode", currency="usd"), +) diff --git a/src/telliot_feeds/reporters/tips/__init__.py b/src/telliot_feeds/reporters/tips/__init__.py index 1f4057ac..d45903dc 100644 --- a/src/telliot_feeds/reporters/tips/__init__.py +++ b/src/telliot_feeds/reporters/tips/__init__.py @@ -239,6 +239,13 @@ def add_multicall_support( multicall3_address="0xcA11bde05977b3631167028862bE2a173976CA11", ) +add_multicall_support( + network="mode-sepolia-vtnhnpim72", + network_id=919, + state_override=False, + multicall3_address="0xcA11bde05977b3631167028862bE2a173976CA11", +) + CATALOG_QUERY_IDS = {query_catalog._entries[tag].query.query_id: tag for tag in query_catalog._entries} CATALOG_QUERY_DATA = {query_catalog._entries[tag].query.query_data: tag for tag in query_catalog._entries} # A list of query types that have a generic source that can take any properly formatted inputs and return a price diff --git a/src/telliot_feeds/sources/price/spot/coingecko.py b/src/telliot_feeds/sources/price/spot/coingecko.py index 50650e94..d8303fc9 100644 --- a/src/telliot_feeds/sources/price/spot/coingecko.py +++ b/src/telliot_feeds/sources/price/spot/coingecko.py @@ -82,6 +82,11 @@ "frax": "frax", "gyd": "gyroscope-gyd", "frxeth": "frax-ether", + "ezeth": "renzo-restaked-eth", + "weeth": "wrapped-eeth", + "wrseth": "wrapped-rseth", + "rseth": "kelp-dao-restaked-eth", + "mode": "mode", } API_KEY = TelliotConfig().api_keys.find(name="coingecko")[0].key diff --git a/src/telliot_feeds/sources/price/spot/curvefiprice.py b/src/telliot_feeds/sources/price/spot/curvefiprice.py index 1956efce..f98537fd 100644 --- a/src/telliot_feeds/sources/price/spot/curvefiprice.py +++ b/src/telliot_feeds/sources/price/spot/curvefiprice.py @@ -21,6 +21,9 @@ "btc": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", "frax": "0x853d955acef822db058eb8505911ed77f175b99e", "frxeth": "0x5e8422345238f34275888049021821e8e08caa1f", + "ezeth": "0xbf5495efe5db9ce00f80364c8b423567e58d2110", + "weeth": "0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee", + "rseth": "0xa1290d69c65a6fe4df752f95823fae25cb99e5a7", } diff --git a/src/telliot_feeds/sources/price/spot/kimexchange.py b/src/telliot_feeds/sources/price/spot/kimexchange.py new file mode 100644 index 00000000..cd4c4c32 --- /dev/null +++ b/src/telliot_feeds/sources/price/spot/kimexchange.py @@ -0,0 +1,91 @@ +from dataclasses import dataclass +from dataclasses import field +from typing import Any + +import requests + +from telliot_feeds.dtypes.datapoint import datetime_now_utc +from telliot_feeds.dtypes.datapoint import OptionalDataPoint +from telliot_feeds.pricing.price_service import WebPriceService +from telliot_feeds.pricing.price_source import PriceSource +from telliot_feeds.utils.log import get_logger + + +logger = get_logger(__name__) +kim_map = { + "mode": "0xdfc7c877a950e49d2610114102175a06c2e3167a", +} + + +class kimexchangePriceService(WebPriceService): + """Kim exchange Price Service in USD and ETH""" + + def __init__(self, **kwargs: Any) -> None: + kwargs["name"] = "Kim exchange subgraph" + kwargs["url"] = "https://api.goldsky.com/api/public" + kwargs["timeout"] = 10.0 + super().__init__(**kwargs) + + async def get_price(self, asset: str, currency: str) -> OptionalDataPoint[float]: + """Implement PriceServiceInterface + + This implementation gets the price from the Kim exchange subgraph + https://api.goldsky.com/api/public/project_clmqdcfcs3f6d2ptj3yp05ndz/subgraphs/Algebra/0.0.1/gn + """ + + asset = asset.lower() + + token = kim_map.get(asset, None) + if not token: + raise Exception("Asset not supported: {}".format(asset)) + + headers = { + "Content-Type": "application/json", + } + + query = "{bundles{maticPriceUSD}token" + f'(id: "{token}")' + "{ derivedMatic } }" + + json_data = {"query": query} + + request_url = self.url + "/project_clmqdcfcs3f6d2ptj3yp05ndz/subgraphs/Algebra/0.0.1/gn" + + with requests.Session() as s: + try: + r = s.post(request_url, headers=headers, json=json_data, timeout=self.timeout) + res = r.json() + data = {"response": res} + + except requests.exceptions.ConnectTimeout: + logger.warning("Timeout Error, No prices retrieved from Kim exchange") + return None, None + + except Exception: + logger.warning("No prices retrieved from kim exchange") + return None, None + + if "error" in data: + logger.error(data) + return None, None + + elif "response" in data: + response = data["response"] + + try: + token_price_eth = float(response["data"]["token"]["derivedMatic"]) + eth_price_usd = float(response["data"]["bundles"][0]["maticPriceUSD"]) + token_price = token_price_eth * eth_price_usd + return token_price, datetime_now_utc() + except KeyError as e: + msg = "Error parsing MaverickV2 response: KeyError: {}".format(e) + logger.critical(msg) + return None, None + + else: + raise Exception("Invalid response from get_url") + + +@dataclass +class kimexchangePriceSource(PriceSource): + asset: str = "" + currency: str = "" + service: kimexchangePriceService = field(default_factory=kimexchangePriceService, init=False) diff --git a/src/telliot_feeds/sources/price/spot/uniswapV3.py b/src/telliot_feeds/sources/price/spot/uniswapV3.py index 0e203df4..09565846 100644 --- a/src/telliot_feeds/sources/price/spot/uniswapV3.py +++ b/src/telliot_feeds/sources/price/spot/uniswapV3.py @@ -28,6 +28,10 @@ "wbtc": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "mnt": "0x3c3a81e81dc49a522a592e7622a7e711c06bf354", "frax": "0x853d955acef822db058eb8505911ed77f175b99e", + "ezeth": "0xbf5495efe5db9ce00f80364c8b423567e58d2110", + "weeth": "0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee", + "wrseth": "0xd2671165570f41bbb3b0097893300b6eb6101e6c", + "rseth": "0xa1290d69c65a6fe4df752f95823fae25cb99e5a7", } diff --git a/src/telliot_feeds/sources/wrseth_source.py b/src/telliot_feeds/sources/wrseth_source.py new file mode 100644 index 00000000..76c2d6fe --- /dev/null +++ b/src/telliot_feeds/sources/wrseth_source.py @@ -0,0 +1,97 @@ +from dataclasses import dataclass +from dataclasses import field +from typing import Any +from typing import Optional + +from telliot_core.apps.telliot_config import TelliotConfig + +from telliot_feeds.dtypes.datapoint import OptionalDataPoint +from telliot_feeds.pricing.price_service import WebPriceService +from telliot_feeds.pricing.price_source import PriceSource +from telliot_feeds.sources.price.spot.coingecko import CoinGeckoSpotPriceSource +from telliot_feeds.sources.price.spot.coinpaprika import CoinpaprikaSpotPriceSource +from telliot_feeds.sources.price.spot.curvefiprice import CurveFiUSDPriceSource +from telliot_feeds.sources.price.spot.uniswapV3 import UniswapV3PriceSource +from telliot_feeds.sources.price_aggregator import PriceAggregator +from telliot_feeds.utils.log import get_logger + +logger = get_logger(__name__) + + +class wrsETHSpotPriceService(WebPriceService): + """Custom wrsETH Price Service""" + + def __init__(self, **kwargs: Any) -> None: + kwargs["name"] = "Custom wrsETH Price Service" + kwargs["url"] = "" + super().__init__(**kwargs) + self.cfg = TelliotConfig() + + def get_wrseth_eth_ratio(self) -> Optional[float]: + # get endpoint + endpoint = self.cfg.endpoints.find(chain_id=34443) + if not endpoint: + logger.error("Endpoint not found for mainnet to get wrseth_eth_ratio") + return None + ep = endpoint[0] + if not ep.connect(): + logger.error("Unable to connect endpoint for mainnet to get wrseth_eth_ratio") + return None + w3 = ep.web3 + # get ratio + wrseth_eth_ratio_bytes = w3.eth.call( + { + "to": "0xbDf612E616432AA8e8D7d8cC1A9c934025371c5C", + "data": "0x679aefce", + } + ) + wrseth_eth_ratio_decoded = w3.toInt(wrseth_eth_ratio_bytes) + wrseth_eth_ratio = w3.fromWei(wrseth_eth_ratio_decoded, "ether") + print(f"Ratio from wrseth contract: {wrseth_eth_ratio}") + return float(wrseth_eth_ratio) + + async def get_price(self, asset: str, currency: str) -> OptionalDataPoint[float]: + """This implementation gets the price of wrsETH from multiple sources and + calculates the price of wrseth using the ratio of wrsETH to rsETH from wrsETH contract. + """ + asset = asset.lower() + currency = currency.lower() + + wrseth_ratio = self.get_wrseth_eth_ratio() + if wrseth_ratio is None: + logger.error("Unable to get wrsETH to rsETH ratio") + return None, None + + source = PriceAggregator( + algorithm="median", + sources=[ + CoinGeckoSpotPriceSource(asset="rseth", currency="usd"), + CurveFiUSDPriceSource(asset="rseth", currency="usd"), + CoinpaprikaSpotPriceSource(asset="rseth-rseth", currency=currency), + UniswapV3PriceSource(asset="rseth", currency=currency), + ], + ) + + wrseth_price, timestamp = await source.fetch_new_datapoint() + if wrseth_price is None: + logger.error("Unable to get wrseth price") + return None, None + return wrseth_price * wrseth_ratio, timestamp + + +@dataclass +class wrsETHSpotPriceSource(PriceSource): + asset: str = "" + currency: str = "" + service: wrsETHSpotPriceService = field(default_factory=wrsETHSpotPriceService, init=False) + + +if __name__ == "__main__": + import asyncio + + async def main() -> None: + source = wrsETHSpotPriceSource(asset="wrseth", currency="usd") + v, _ = await source.fetch_new_datapoint() + print(v) + + asyncio.run(main()) diff --git a/tests/feeds/test_ezeth_usd_feed.py b/tests/feeds/test_ezeth_usd_feed.py new file mode 100644 index 00000000..a13e492a --- /dev/null +++ b/tests/feeds/test_ezeth_usd_feed.py @@ -0,0 +1,21 @@ +import statistics + +import pytest + +from telliot_feeds.feeds.ezeth_usd_feed import ezeth_usd_median_feed + + +@pytest.mark.asyncio +async def test_ezeth_usd_median_feed(caplog): + """Retrieve median ezETH/USD price.""" + v, _ = await ezeth_usd_median_feed.source.fetch_new_datapoint() + + assert v is not None + assert v > 0 + assert "sources used in aggregate: 4" in caplog.text.lower() + print(f"EZETH/USD Price: {v}") + # Get list of data sources from sources dict + source_prices = ezeth_usd_median_feed.source.latest[0] + + # Make sure error is less than decimal tolerance + assert (v - statistics.median([source_prices])) < 10**-6 diff --git a/tests/feeds/test_mode_usd_feed.py b/tests/feeds/test_mode_usd_feed.py new file mode 100644 index 00000000..0f01ae34 --- /dev/null +++ b/tests/feeds/test_mode_usd_feed.py @@ -0,0 +1,22 @@ +import statistics + +import pytest + +from telliot_feeds.feeds.mode_usd_feed import mode_usd_median_feed + + +@pytest.mark.asyncio +async def test_mode_usd_feed(caplog): + """Retrieve median MODE/USD price converted to wUSDM by ratio""" + v, _ = await mode_usd_median_feed.source.fetch_new_datapoint() + + assert v is not None + assert v > 0 + assert "sources used in aggregate: 3" in caplog.text.lower() + print(f"mode/usd Price: {v}") + + # Get list of data sources from sources dict + source_prices = [source.latest[0] for source in mode_usd_median_feed.source.sources if source.latest[0]] + + # Make sure error is less than decimal tolerance + assert (v - statistics.median(source_prices)) < 10**-6 diff --git a/tests/feeds/test_rseth_usd_feed.py b/tests/feeds/test_rseth_usd_feed.py new file mode 100644 index 00000000..ffd3a6d5 --- /dev/null +++ b/tests/feeds/test_rseth_usd_feed.py @@ -0,0 +1,21 @@ +import statistics + +import pytest + +from telliot_feeds.feeds.rseth_usd_feed import rseth_usd_median_feed + + +@pytest.mark.asyncio +async def test_rseth_usd_median_feed(caplog): + """Retrieve median rsETH/USD price.""" + v, _ = await rseth_usd_median_feed.source.fetch_new_datapoint() + + assert v is not None + assert v > 0 + assert "sources used in aggregate: 4" in caplog.text.lower() + print(f"rsETH/USD Price: {v}") + # Get list of data sources from sources dict + source_prices = rseth_usd_median_feed.source.latest[0] + + # Make sure error is less than decimal tolerance + assert (v - statistics.median([source_prices])) < 10**-6 diff --git a/tests/feeds/test_weeth_usd_feed.py b/tests/feeds/test_weeth_usd_feed.py new file mode 100644 index 00000000..e49d5f1e --- /dev/null +++ b/tests/feeds/test_weeth_usd_feed.py @@ -0,0 +1,21 @@ +import statistics + +import pytest + +from telliot_feeds.feeds.weeth_usd_feed import weeth_usd_median_feed + + +@pytest.mark.asyncio +async def test_weeth_usd_median_feed(caplog): + """Retrieve median weETH/USD price.""" + v, _ = await weeth_usd_median_feed.source.fetch_new_datapoint() + + assert v is not None + assert v > 0 + assert "sources used in aggregate: 4" in caplog.text.lower() + print(f"weETH/USD Price: {v}") + # Get list of data sources from sources dict + source_prices = weeth_usd_median_feed.source.latest[0] + + # Make sure error is less than decimal tolerance + assert (v - statistics.median([source_prices])) < 10**-6 diff --git a/tests/feeds/test_wrseth_usd_feed.py b/tests/feeds/test_wrseth_usd_feed.py new file mode 100644 index 00000000..dee4c7be --- /dev/null +++ b/tests/feeds/test_wrseth_usd_feed.py @@ -0,0 +1,21 @@ +import statistics + +import pytest + +from telliot_feeds.feeds.wrseth_usd_feed import wrseth_usd_feed + + +@pytest.mark.asyncio +async def test_wrseth_usd_feed(caplog): + """Retrieve median WrsETH/USD price.""" + v, _ = await wrseth_usd_feed.source.fetch_new_datapoint() + + assert v is not None + assert v > 0 + assert "sources used in aggregate: 4" in caplog.text.lower() + print(f"WrsETH/USD Price: {v}") + # Get list of data sources from sources dict + source_prices = wrseth_usd_feed.source.latest[0] + + # Make sure error is less than decimal tolerance + assert (v - statistics.median([source_prices])) < 10**-6