diff --git a/src/telliot_feeds/queries/abi_query.py b/src/telliot_feeds/queries/abi_query.py index 1344cdba..b38b962e 100644 --- a/src/telliot_feeds/queries/abi_query.py +++ b/src/telliot_feeds/queries/abi_query.py @@ -1,10 +1,15 @@ +import codecs from typing import ClassVar from typing import Optional +import pkg_resources from clamfig import deserialize from clamfig.base import Registry from eth_abi import decode_abi from eth_abi import encode_abi +from eth_abi.encoding import TextStringEncoder +from eth_abi.utils.numeric import ceil32 +from eth_abi.utils.padding import zpad_right from telliot_feeds.queries.query import OracleQuery from telliot_feeds.utils.log import get_logger @@ -13,6 +18,28 @@ logger = get_logger(__name__) +"""This is a temporary fix for the bug in eth-abi versions < 4.0.0 +when empty strings are encoded extra zeros were being added eth-abi version >= 4.0.0 addresses this issue +but upgrading the package will break the telliot_feeds package due dependency version conflicts""" +version = pkg_resources.get_distribution("eth-abi").version +pkg_version = int(version.split(".")[0]) + + +if pkg_version < 4: + + @classmethod + def encode(cls, value): # type: ignore + cls.validate_value(value) + + value_as_bytes = codecs.encode(value, "utf8") + value_length = len(value_as_bytes) + encoded_size = encode_abi(["uint256"], [value_length]) + padded_value = zpad_right(value_as_bytes, ceil32(value_length)) + return encoded_size + padded_value + + TextStringEncoder.encode = encode # type: ignore + + class AbiQuery(OracleQuery): """An Oracle Query that uses ABI-encoding to compute the query_data. diff --git a/src/telliot_feeds/queries/inflation_data.py b/src/telliot_feeds/queries/inflation_data.py new file mode 100644 index 00000000..dad01856 --- /dev/null +++ b/src/telliot_feeds/queries/inflation_data.py @@ -0,0 +1,47 @@ +"""Abi query for inflation data spec""" +import logging +from dataclasses import dataclass +from typing import Optional + +from telliot_feeds.dtypes.float_type import UnsignedFloatType +from telliot_feeds.dtypes.value_type import ValueType +from telliot_feeds.queries.abi_query import AbiQuery + + +logger = logging.getLogger(__name__) + + +@dataclass +class InflationData(AbiQuery): + """ + More info: https://github.com/tellor-io/dataSpecs/blob/main/types/InflationData.md + + Attributes: + - location: The area of the world where the data was collected (e.g. USA) + - agency: The acronym for or full name of the agency that collected the data (e.g. BLS) + - category: The category should describe which basket of goods is used to calculate inflation of (e.g. housing) + - description: The description should include additional information needed to differentiate the + data.(e.g. index) + """ + + location: Optional[str] = None + agency: Optional[str] = None + category: Optional[str] = None + description: Optional[str] = None + + #: ABI used for encoding/decoding parameters + abi = [ + {"name": "location", "type": "string"}, + {"name": "agency", "type": "string"}, + {"name": "category", "type": "string"}, + {"name": "description", "type": "string"}, + ] + + @property + def value_type(self) -> ValueType: + """Data type returned for a InflationData query. + + - `ufixed256x18`: 256-bit unsigned integer with 18 decimals of precision + - `packed`: false + """ + return UnsignedFloatType(abi_type="ufixed256x18", packed=False) diff --git a/tests/queries/test_inflation_data_query.py b/tests/queries/test_inflation_data_query.py new file mode 100644 index 00000000..f478331f --- /dev/null +++ b/tests/queries/test_inflation_data_query.py @@ -0,0 +1,17 @@ +from telliot_feeds.queries.inflation_data import InflationData + + +def test_inflation_data_query(): + """Test InflationData query encoding""" + q = InflationData( + location="USA", + agency="BLS", + category="", + description="CPI", + ) + + assert ( + q.query_data.hex() + == "00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d496e666c6174696f6e44617461000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000355534100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003424c530000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034350490000000000000000000000000000000000000000000000000000000000" # noqa: E501 + ) + assert q.query_id.hex() == "389577823bc36cc44f87d115fcf1d681b9a12be480d449e85013a8cd788fc58a"