diff --git a/apps/hip-3-pusher/README.md b/apps/hip-3-pusher/README.md index e69de29bb2..a01318e641 100644 --- a/apps/hip-3-pusher/README.md +++ b/apps/hip-3-pusher/README.md @@ -0,0 +1,9 @@ +# HIP-3 Pusher + +`hip-3-pusher` is intended to serve as an oracle updater for +[HIP-3 markets](https://hyperliquid.gitbook.io/hyperliquid-docs/hyperliquid-improvement-proposals-hips/hip-3-builder-deployed-perpetuals). + +Currently it: +- Sources market data from Hyperliquid, Pyth Lazer, and Pythnet +- Supports KMS for signing oracle updates +- Provides telemetry to Pyth's internal observability system diff --git a/apps/hip-3-pusher/pyproject.toml b/apps/hip-3-pusher/pyproject.toml index 3b19365bc6..04358bc306 100644 --- a/apps/hip-3-pusher/pyproject.toml +++ b/apps/hip-3-pusher/pyproject.toml @@ -1,18 +1,16 @@ [project] name = "hip-3-pusher" -version = "0.1.3" +version = "0.1.4" description = "Hyperliquid HIP-3 market oracle pusher" readme = "README.md" -requires-python = ">=3.13" +requires-python = "==3.13.*" dependencies = [ - "asn1crypto>=1.5.1", - "boto3>=1.40.31", - "cryptography>=45.0.7", - "hyperliquid-python-sdk>=0.19.0", - "loguru>=0.7.3", - "opentelemetry-exporter-prometheus>=0.58b0", - "opentelemetry-sdk>=1.37.0", - "prometheus-client>=0.23.1", - "toml>=0.10.2", - "websockets>=15.0.1", + "boto3~=1.40.34", + "cryptography~=46.0.1", + "hyperliquid-python-sdk~=0.19.0", + "loguru~=0.7.3", + "opentelemetry-exporter-prometheus~=0.58b0", + "opentelemetry-sdk~=1.37.0", + "prometheus-client~=0.23.1", + "websockets~=15.0.1", ] diff --git a/apps/hip-3-pusher/src/config.py b/apps/hip-3-pusher/src/config.py new file mode 100644 index 0000000000..289bd455cb --- /dev/null +++ b/apps/hip-3-pusher/src/config.py @@ -0,0 +1,45 @@ +from pydantic import BaseModel + + +class KMSConfig(BaseModel): + enable_kms: bool + aws_region_name: str + key_path: str + access_key_id_path: str + secret_access_key_path: str + + +class LazerConfig(BaseModel): + lazer_urls: list[str] + lazer_api_key: str + base_feed_id: int + base_feed_exponent: int + quote_feed_id: int + quote_feed_exponent: int + + +class HermesConfig(BaseModel): + hermes_urls: list[str] + base_feed_id: str + base_feed_exponent: int + quote_feed_id: str + quote_feed_exponent: int + + +class HyperliquidConfig(BaseModel): + hyperliquid_ws_urls: list[str] + market_name: str + market_symbol: str + use_testnet: bool + oracle_pusher_key_path: str + publish_interval: float + enable_publish: bool + + +class Config(BaseModel): + stale_price_threshold_seconds: int + prometheus_port: int + hyperliquid: HyperliquidConfig + kms: KMSConfig + lazer: LazerConfig + hermes: HermesConfig diff --git a/apps/hip-3-pusher/src/hermes_listener.py b/apps/hip-3-pusher/src/hermes_listener.py index 02adb2e1aa..53500e0b5c 100644 --- a/apps/hip-3-pusher/src/hermes_listener.py +++ b/apps/hip-3-pusher/src/hermes_listener.py @@ -4,17 +4,18 @@ import time import websockets -from price_state import PriceState +from config import Config +from price_state import PriceState, PriceUpdate class HermesListener: """ Subscribe to Hermes price updates for needed feeds. """ - def __init__(self, config, price_state: PriceState): - self.hermes_urls = config["hermes"]["hermes_urls"] - self.base_feed_id = config["hermes"]["base_feed_id"] - self.quote_feed_id = config["hermes"]["quote_feed_id"] + def __init__(self, config: Config, price_state: PriceState): + self.hermes_urls = config.hermes.hermes_urls + self.base_feed_id = config.hermes.base_feed_id + self.quote_feed_id = config.hermes.quote_feed_id self.price_state = price_state def get_subscribe_request(self): @@ -71,10 +72,10 @@ def parse_hermes_message(self, data): expo = price_object["expo"] publish_time = price_object["publish_time"] logger.debug("Hermes update: {} {} {} {}", id, price, expo, publish_time) + now = time.time() if id == self.base_feed_id: - self.price_state.hermes_base_price = price + self.price_state.hermes_base_price = PriceUpdate(price, now) if id == self.quote_feed_id: - self.price_state.hermes_quote_price = price - self.price_state.latest_hermes_timestamp = time.time() + self.price_state.hermes_quote_price = PriceUpdate(price, now) except Exception as e: logger.error("parse_hermes_message error: {}", e) diff --git a/apps/hip-3-pusher/src/hyperliquid_listener.py b/apps/hip-3-pusher/src/hyperliquid_listener.py index aed7e4ea74..db231e7a32 100644 --- a/apps/hip-3-pusher/src/hyperliquid_listener.py +++ b/apps/hip-3-pusher/src/hyperliquid_listener.py @@ -1,10 +1,16 @@ +import asyncio +import json +import websockets from loguru import logger import time -from hyperliquid.info import Info -from hyperliquid.utils.constants import TESTNET_API_URL, MAINNET_API_URL +from config import Config +from price_state import PriceState, PriceUpdate -from price_state import PriceState +# This will be in config, but note here. +# Other RPC providers exist but so far we've seen their support is incomplete. +HYPERLIQUID_MAINNET_WS_URL = "wss://api.hyperliquid.xyz/ws" +HYPERLIQUID_TESTNET_WS_URL = "wss://api.hyperliquid-testnet.xyz/ws" class HyperliquidListener: @@ -12,24 +18,60 @@ class HyperliquidListener: Subscribe to any relevant Hyperliquid websocket streams See https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket """ - def __init__(self, config: dict, price_state: PriceState): - self.market_symbol = config["hyperliquid"]["market_symbol"] - url = TESTNET_API_URL if config["hyperliquid"].get("use_testnet", True) else MAINNET_API_URL - self.info = Info(base_url=url) + def __init__(self, config: Config, price_state: PriceState): + self.hyperliquid_ws_urls = config.hyperliquid.hyperliquid_ws_urls + self.market_symbol = config.hyperliquid.market_symbol self.price_state = price_state - def subscribe(self): - self.info.subscribe({"type": "activeAssetCtx", "coin": self.market_symbol}, self.on_activeAssetCtx) - - def on_activeAssetCtx(self, message): - """ - Parse oraclePx and markPx from perp context update - - :param message: activeAssetCtx websocket update message - :return: None - """ - ctx = message["data"]["ctx"] - self.price_state.hl_oracle_price = ctx["oraclePx"] - self.price_state.hl_mark_price = ctx["markPx"] - logger.debug("on_activeAssetCtx: oraclePx: {} marketPx: {}", self.price_state.hl_oracle_price, self.price_state.hl_mark_price) - self.price_state.latest_hl_timestamp = time.time() + def get_subscribe_request(self, asset): + return { + "method": "subscribe", + "subscription": {"type": "activeAssetCtx", "coin": asset} + } + + async def subscribe_all(self): + await asyncio.gather(*(self.subscribe_single(hyperliquid_ws_url) for hyperliquid_ws_url in self.hyperliquid_ws_urls)) + + async def subscribe_single(self, url): + while True: + try: + await self.subscribe_single_inner(url) + except websockets.ConnectionClosed: + logger.error("Connection to {} closed; retrying", url) + except Exception as e: + logger.exception("Error on {}: {}", url, e) + + async def subscribe_single_inner(self, url): + async with websockets.connect(url) as ws: + subscribe_request = self.get_subscribe_request(self.market_symbol) + await ws.send(json.dumps(subscribe_request)) + logger.info("Sent subscribe request to {}", url) + + # listen for updates + async for message in ws: + try: + data = json.loads(message) + channel = data.get("channel", None) + if not channel: + logger.error("No channel in message: {}", data) + elif channel == "subscriptionResponse": + logger.debug("Received subscription response: {}", data) + elif channel == "error": + logger.error("Received Hyperliquid error response: {}", data) + elif channel == "activeAssetCtx": + self.parse_hyperliquid_ws_message(data) + else: + logger.error("Received unknown channel: {}", channel) + except json.JSONDecodeError as e: + logger.error("Failed to decode JSON message: {} error: {}", message, e) + + def parse_hyperliquid_ws_message(self, message): + try: + ctx = message["data"]["ctx"] + now = time.time() + self.price_state.hl_oracle_price = PriceUpdate(ctx["oraclePx"], now) + self.price_state.hl_mark_price = PriceUpdate(ctx["markPx"], now) + logger.debug("on_activeAssetCtx: oraclePx: {} marketPx: {}", self.price_state.hl_oracle_price, + self.price_state.hl_mark_price) + except Exception as e: + logger.error("parse_hyperliquid_ws_message error: message: {} e: {}", message, e) diff --git a/apps/hip-3-pusher/src/kms_signer.py b/apps/hip-3-pusher/src/kms_signer.py index 294c1cf5f6..b7d9c97146 100644 --- a/apps/hip-3-pusher/src/kms_signer.py +++ b/apps/hip-3-pusher/src/kms_signer.py @@ -1,6 +1,8 @@ import boto3 -from asn1crypto import core +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature from eth_account.messages import encode_typed_data, _hash_eip191_message +from eth_keys.backends.native.ecdsa import N as SECP256K1_N from eth_keys.datatypes import Signature from eth_utils import keccak, to_hex from hyperliquid.exchange import Exchange @@ -8,19 +10,24 @@ from hyperliquid.utils.signing import get_timestamp_ms, action_hash, construct_phantom_agent, l1_payload from loguru import logger +from config import Config + +SECP256K1_N_HALF = SECP256K1_N // 2 + class KMSSigner: - def __init__(self, key_id, aws_region_name, use_testnet): + def __init__(self, config: Config): + use_testnet = config.hyperliquid.use_testnet url = TESTNET_API_URL if use_testnet else MAINNET_API_URL self.oracle_publisher_exchange: Exchange = Exchange(wallet=None, base_url=url) + self.client = self._init_client(config) - self.key_id = key_id - self.client = boto3.client("kms", region_name=aws_region_name) # Fetch public key once so we can derive address and check recovery id - pub_der = self.client.get_public_key(KeyId=key_id)["PublicKey"] - - from cryptography.hazmat.primitives import serialization - pub = serialization.load_der_public_key(pub_der) + key_path = config.kms.key_path + self.key_id = open(key_path, "r").read().strip() + self.pubkey_der = self.client.get_public_key(KeyId=self.key_id)["PublicKey"] + # Construct eth address to log + pub = serialization.load_der_public_key(self.pubkey_der) numbers = pub.public_numbers() x = numbers.x.to_bytes(32, "big") y = numbers.y.to_bytes(32, "big") @@ -29,6 +36,22 @@ def __init__(self, key_id, aws_region_name, use_testnet): self.address = "0x" + keccak(uncompressed[1:])[-20:].hex() logger.info("KMSSigner address: {}", self.address) + def _init_client(self, config): + aws_region_name = config.kms.aws_region_name + access_key_id_path = config.kms.access_key_id_path + access_key_id = open(access_key_id_path, "r").read().strip() + secret_access_key_path = config.kms.secret_access_key_path + secret_access_key = open(secret_access_key_path, "r").read().strip() + + return boto3.client( + "kms", + region_name=aws_region_name, + aws_access_key_id=access_key_id, + aws_secret_access_key=secret_access_key, + # can specify an endpoint for e.g. LocalStack + # endpoint_url="http://localhost:4566" + ) + def set_oracle(self, dex, oracle_pxs, all_mark_pxs, external_perp_pxs): timestamp = get_timestamp_ms() oracle_pxs_wire = sorted(list(oracle_pxs.items())) @@ -60,34 +83,39 @@ def sign_l1_action(self, action, nonce, is_mainnet): data = l1_payload(phantom_agent) structured_data = encode_typed_data(full_message=data) message_hash = _hash_eip191_message(structured_data) - signed = self.sign_message(message_hash) - return {"r": to_hex(signed["r"]), "s": to_hex(signed["s"]), "v": signed["v"]} + return self.sign_message(message_hash) - def sign_message(self, message_hash: bytes): + def sign_message(self, message_hash: bytes) -> dict: + # Send message hash to KMS for signing resp = self.client.sign( KeyId=self.key_id, Message=message_hash, MessageType="DIGEST", SigningAlgorithm="ECDSA_SHA_256", # required for secp256k1 ) - der_sig = resp["Signature"] - - seq = core.Sequence.load(der_sig) - r = int(seq[0].native) - s = int(seq[1].native) - - for recovery_id in (0, 1): - candidate = Signature(vrs=(recovery_id, r, s)) - pubkey = candidate.recover_public_key_from_msg_hash(message_hash) - if pubkey.to_bytes() == self.public_key_bytes: - v = recovery_id + 27 - break - else: - raise ValueError("Failed to determine recovery id") - - return { - "r": r, - "s": s, - "v": v, - "signature": Signature(vrs=(v, r, s)).to_bytes().hex(), - } + kms_signature = resp["Signature"] + # Decode the KMS DER signature -> (r, s) + r, s = decode_dss_signature(kms_signature) + # Ethereum requires low-s form + if s > SECP256K1_N_HALF: + s = SECP256K1_N - s + # Parse KMS public key into uncompressed secp256k1 bytes + # TODO: Pull this into init + pubkey = serialization.load_der_public_key(self.pubkey_der) + pubkey_bytes = pubkey.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint, + ) + # Strip leading 0x04 (uncompressed point indicator) + raw_pubkey_bytes = pubkey_bytes[1:] + # Try both recovery ids + for v in (0, 1): + sig_obj = Signature(vrs=(v, r, s)) + recovered_pub = sig_obj.recover_public_key_from_msg_hash(message_hash) + if recovered_pub.to_bytes() == raw_pubkey_bytes: + return { + "r": to_hex(r), + "s": to_hex(s), + "v": v + 27, + } + raise ValueError("Could not recover public key; signature mismatch") diff --git a/apps/hip-3-pusher/src/lazer_listener.py b/apps/hip-3-pusher/src/lazer_listener.py index 58631c512d..f173db5636 100644 --- a/apps/hip-3-pusher/src/lazer_listener.py +++ b/apps/hip-3-pusher/src/lazer_listener.py @@ -4,18 +4,19 @@ import time import websockets -from price_state import PriceState +from config import Config +from price_state import PriceState, PriceUpdate class LazerListener: """ Subscribe to Lazer price updates for needed feeds. """ - def __init__(self, config, price_state: PriceState): - self.lazer_urls = config["lazer"]["lazer_urls"] - self.api_key = config["lazer"]["lazer_api_key"] - self.base_feed_id = config["lazer"]["base_feed_id"] - self.quote_feed_id = config["lazer"]["quote_feed_id"] + def __init__(self, config: Config, price_state: PriceState): + self.lazer_urls = config.lazer.lazer_urls + self.api_key = config.lazer.lazer_api_key + self.base_feed_id = config.lazer.base_feed_id + self.quote_feed_id = config.lazer.quote_feed_id self.price_state = price_state def get_subscribe_request(self, subscription_id: int): @@ -52,7 +53,7 @@ async def subscribe_single_inner(self, router_url): subscribe_request = self.get_subscribe_request(1) await ws.send(json.dumps(subscribe_request)) - logger.info("Sent Lazer subscribe request to {}", self.lazer_urls[0]) + logger.info("Sent Lazer subscribe request to {}", router_url) # listen for updates async for message in ws: @@ -74,15 +75,15 @@ def parse_lazer_message(self, data): return price_feeds = data["parsed"]["priceFeeds"] logger.debug("price_feeds: {}", price_feeds) + now = time.time() for feed_update in price_feeds: feed_id = feed_update.get("priceFeedId", None) price = feed_update.get("price", None) if feed_id is None or price is None: continue if feed_id == self.base_feed_id: - self.price_state.lazer_base_price = price + self.price_state.lazer_base_price = PriceUpdate(price, now) if feed_id == self.quote_feed_id: - self.price_state.lazer_quote_price = price - self.price_state.latest_lazer_timestamp = time.time() + self.price_state.lazer_quote_price = PriceUpdate(price, now) except Exception as e: logger.error("parse_lazer_message error: {}", e) diff --git a/apps/hip-3-pusher/src/main.py b/apps/hip-3-pusher/src/main.py index c599e0806e..dbb7e38772 100644 --- a/apps/hip-3-pusher/src/main.py +++ b/apps/hip-3-pusher/src/main.py @@ -3,8 +3,9 @@ from loguru import logger import os import sys -import toml +import tomllib +from config import Config from hyperliquid_listener import HyperliquidListener from lazer_listener import LazerListener from hermes_listener import HermesListener @@ -21,8 +22,10 @@ def load_config(): help="hip3-agent config file", ) config_path = parser.parse_args().config - with open(config_path, "r") as config_file: - config = toml.load(config_file) + with open(config_path, "rb") as config_file: + config_toml = tomllib.load(config_file) + config = Config(**config_toml) + logger.debug("Config loaded: {}", config) return config @@ -46,10 +49,9 @@ async def main(): lazer_listener = LazerListener(config, price_state) hermes_listener = HermesListener(config, price_state) - # TODO: Probably pull this out of the sdk so we can handle reconnects. - hyperliquid_listener.subscribe() await asyncio.gather( publisher.run(), + hyperliquid_listener.subscribe_all(), lazer_listener.subscribe_all(), hermes_listener.subscribe_all(), ) diff --git a/apps/hip-3-pusher/src/metrics.py b/apps/hip-3-pusher/src/metrics.py index 9c5bb576df..66dc78a4df 100644 --- a/apps/hip-3-pusher/src/metrics.py +++ b/apps/hip-3-pusher/src/metrics.py @@ -3,14 +3,16 @@ from opentelemetry.metrics import get_meter_provider, set_meter_provider from opentelemetry.sdk.metrics import MeterProvider +from config import Config + METER_NAME = "hip3pusher" class Metrics: - def __init__(self, config): + def __init__(self, config: Config): # Adapted from opentelemetry-exporter-prometheus example code. # Start Prometheus client - start_http_server(port=config["prometheus_port"]) + start_http_server(port=config.prometheus_port) # Exporter to export metrics to Prometheus reader = PrometheusMetricReader() # Meter is responsible for creating and recording metrics diff --git a/apps/hip-3-pusher/src/price_state.py b/apps/hip-3-pusher/src/price_state.py index f7d3a13650..078d5a08bd 100644 --- a/apps/hip-3-pusher/src/price_state.py +++ b/apps/hip-3-pusher/src/price_state.py @@ -1,73 +1,83 @@ from loguru import logger import time +from config import Config + DEFAULT_STALE_PRICE_THRESHOLD_SECONDS = 5 +class PriceUpdate: + def __init__(self, price, timestamp): + self.price = price + self.timestamp = timestamp + + def __str__(self): + return f"PriceUpdate(price={self.price}, timestamp={self.timestamp})" + + def time_diff(self, now): + return now - self.timestamp + + class PriceState: """ Maintain latest prices seen across listeners and publisher. """ - def __init__(self, config): - self.stale_price_threshold_seconds = config.get("stale_price_threshold_seconds", DEFAULT_STALE_PRICE_THRESHOLD_SECONDS) - now = time.time() + def __init__(self, config: Config): + self.stale_price_threshold_seconds = config.stale_price_threshold_seconds - self.hl_oracle_price = None - self.hl_mark_price = None - self.latest_hl_timestamp = now + self.hl_oracle_price: PriceUpdate | None = None + self.hl_mark_price: PriceUpdate | None = None - self.lazer_base_price = None - self.lazer_base_exponent = config["lazer"]["base_feed_exponent"] - self.lazer_quote_price = None - self.lazer_quote_exponent = config["lazer"]["quote_feed_exponent"] - self.latest_lazer_timestamp = now + self.lazer_base_price: PriceUpdate | None = None + self.lazer_base_exponent = config.lazer.base_feed_exponent + self.lazer_quote_price: PriceUpdate | None = None + self.lazer_quote_exponent = config.lazer.quote_feed_exponent - self.hermes_base_price = None - self.hermes_base_exponent = config["hermes"]["base_feed_exponent"] - self.hermes_quote_price = None - self.hermes_quote_exponent = config["hermes"]["quote_feed_exponent"] - self.latest_hermes_timestamp = now + self.hermes_base_price: PriceUpdate | None = None + self.hermes_base_exponent = config.hermes.base_feed_exponent + self.hermes_quote_price: PriceUpdate | None = None + self.hermes_quote_exponent = config.hermes.quote_feed_exponent def get_current_oracle_price(self): now = time.time() if self.hl_oracle_price: - time_diff = now - self.latest_hl_timestamp + time_diff = self.hl_oracle_price.time_diff(now) if time_diff < self.stale_price_threshold_seconds: - return self.hl_oracle_price + return self.hl_oracle_price.price else: logger.error("Hyperliquid oracle price stale by {} seconds", time_diff) else: logger.error("Hyperliquid oracle price not received yet") - # fall back to Hermes - if self.hermes_base_price and self.hermes_quote_price: - time_diff = now - self.latest_hermes_timestamp - if time_diff < self.stale_price_threshold_seconds: - return self.get_hermes_price() - else: - logger.error("Hermes price stale by {} seconds", time_diff) - else: - logger.error("Hermes base/quote prices not received yet") - # fall back to Lazer if self.lazer_base_price and self.lazer_quote_price: - time_diff = now - self.latest_lazer_timestamp - if time_diff < self.stale_price_threshold_seconds: + max_time_diff = max(self.lazer_base_price.time_diff(now), self.lazer_quote_price.time_diff(now)) + if max_time_diff < self.stale_price_threshold_seconds: return self.get_lazer_price() else: - logger.error("Lazer price stale by {} seconds", time_diff) + logger.error("Lazer price stale by {} seconds", max_time_diff) else: logger.error("Lazer base/quote prices not received yet") + # fall back to Hermes + if self.hermes_base_price and self.hermes_quote_price: + max_time_diff = max(self.hermes_base_price.time_diff(now), self.hermes_quote_price.time_diff(now)) + if max_time_diff < self.stale_price_threshold_seconds: + return self.get_hermes_price() + else: + logger.error("Hermes price stale by {} seconds", max_time_diff) + else: + logger.error("Hermes base/quote prices not received yet") + logger.error("All prices missing or stale!") return None def get_hermes_price(self): - base_price = float(self.hermes_base_price) / (10.0 ** -self.hermes_base_exponent) - quote_price = float(self.hermes_quote_price) / (10.0 ** -self.hermes_quote_exponent) + base_price = float(self.hermes_base_price.price) / (10.0 ** -self.hermes_base_exponent) + quote_price = float(self.hermes_quote_price.price) / (10.0 ** -self.hermes_quote_exponent) return str(round(base_price / quote_price, 2)) def get_lazer_price(self): - base_price = float(self.lazer_base_price) / (10.0 ** -self.lazer_base_exponent) - quote_price = float(self.lazer_quote_price) / (10.0 ** -self.lazer_quote_exponent) + base_price = float(self.lazer_base_price.price) / (10.0 ** -self.lazer_base_exponent) + quote_price = float(self.lazer_quote_price.price) / (10.0 ** -self.lazer_quote_exponent) return str(round(base_price / quote_price, 2)) diff --git a/apps/hip-3-pusher/src/publisher.py b/apps/hip-3-pusher/src/publisher.py index 23e5f90af1..73a047f149 100644 --- a/apps/hip-3-pusher/src/publisher.py +++ b/apps/hip-3-pusher/src/publisher.py @@ -7,6 +7,7 @@ from hyperliquid.exchange import Exchange from hyperliquid.utils.constants import TESTNET_API_URL, MAINNET_API_URL +from config import Config from kms_signer import KMSSigner from metrics import Metrics from price_state import PriceState @@ -18,30 +19,27 @@ class Publisher: See https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/hip-3-deployer-actions """ - def __init__(self, config: dict, price_state: PriceState, metrics: Metrics): - self.publish_interval = float(config["hyperliquid"]["publish_interval"]) + def __init__(self, config: Config, price_state: PriceState, metrics: Metrics): + self.publish_interval = float(config.hyperliquid.publish_interval) self.kms_signer = None self.enable_kms = False - self.use_testnet = config["hyperliquid"].get("use_testnet", True) + self.use_testnet = config.hyperliquid.use_testnet - if config["kms"]["enable_kms"]: + if config.kms.enable_kms: self.enable_kms = True oracle_account = None - kms_key_path = config["kms"]["key_path"] - kms_key_id = open(kms_key_path, "r").read().strip() - self.kms_signer = KMSSigner(kms_key_id, config["kms"]["aws_region_name"], self.use_testnet) + self.kms_signer = KMSSigner(config) else: - oracle_pusher_key_path = config["hyperliquid"]["oracle_pusher_key_path"] + oracle_pusher_key_path = config.hyperliquid.oracle_pusher_key_path oracle_pusher_key = open(oracle_pusher_key_path, "r").read().strip() oracle_account: LocalAccount = Account.from_key(oracle_pusher_key) - del oracle_pusher_key logger.info("oracle pusher local pubkey: {}", oracle_account.address) url = TESTNET_API_URL if self.use_testnet else MAINNET_API_URL self.oracle_publisher_exchange: Exchange = Exchange(wallet=oracle_account, base_url=url) - self.market_name = config["hyperliquid"]["market_name"] - self.market_symbol = config["hyperliquid"]["market_symbol"] - self.enable_publish = config["hyperliquid"].get("enable_publish", False) + self.market_name = config.hyperliquid.market_name + self.market_symbol = config.hyperliquid.market_symbol + self.enable_publish = config.hyperliquid.enable_publish self.price_state = price_state self.metrics = metrics @@ -70,6 +68,8 @@ def publish(self): # mark_pxs.append({self.market_symbol: self.price_state.hl_mark_price}) external_perp_pxs = {} + # TODO: "Each update can change oraclePx and markPx by at most 1%." + # TODO: "The markPx cannot be updated such that open interest would be 10x the open interest cap." if self.enable_publish: if self.enable_kms: diff --git a/apps/hip-3-pusher/uv.lock b/apps/hip-3-pusher/uv.lock index b9b1728100..dea3972cd8 100644 --- a/apps/hip-3-pusher/uv.lock +++ b/apps/hip-3-pusher/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 3 -requires-python = ">=3.13" +requires-python = "==3.13.*" [[package]] name = "annotated-types" @@ -11,15 +11,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] -[[package]] -name = "asn1crypto" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/de/cf/d547feed25b5244fcb9392e288ff9fdc3280b10260362fc45d37a798a6ee/asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", size = 121080, upload-time = "2022-03-15T14:46:52.889Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/7f/09065fd9e27da0eda08b4d6897f1c13535066174cc023af248fc2a8d5e5a/asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67", size = 105045, upload-time = "2022-03-15T14:46:51.055Z" }, -] - [[package]] name = "bitarray" version = "3.7.1" @@ -44,30 +35,30 @@ wheels = [ [[package]] name = "boto3" -version = "1.40.31" +version = "1.40.36" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/e6/1a8b1710245aac792ea283051727f4e7f29b4bfb85fd887f4c25aa85b4eb/boto3-1.40.31.tar.gz", hash = "sha256:8c5f1270f09431694412f326cfb5ac9786d41ea3bc6ac54cbb7161d40afc660d", size = 111606, upload-time = "2025-09-15T19:38:46.136Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/21/7bc857b155e8264c92b6fa8e0860a67dc01a19cbe6ba4342500299f2ae5b/boto3-1.40.36.tar.gz", hash = "sha256:bfc1f3d5c4f5d12b8458406b8972f8794ac57e2da1ee441469e143bc0440a5c3", size = 111552, upload-time = "2025-09-22T19:26:17.357Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/79/22fd4a4a61cb87f893804d8a36a834c69849a8fe2b0d9e28c2676824bff1/boto3-1.40.31-py3-none-any.whl", hash = "sha256:61d5f9975c54ff919a24ff9d472c6c09c8a443a083fe56d30c04fc22d22ac42b", size = 139343, upload-time = "2025-09-15T19:38:44.707Z" }, + { url = "https://files.pythonhosted.org/packages/70/4c/428b728d5cf9003f83f735d10dd522945ab20c7d67e6c987909f29be12a0/boto3-1.40.36-py3-none-any.whl", hash = "sha256:d7c1fe033f491f560cd26022a9dcf28baf877ae854f33bc64fffd0df3b9c98be", size = 139345, upload-time = "2025-09-22T19:26:15.194Z" }, ] [[package]] name = "botocore" -version = "1.40.31" +version = "1.40.36" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/8a/6ed2ccd9f6b8930ed15e755667f8f5f32a568cf4e3bf31a8526dcf4ce562/botocore-1.40.31.tar.gz", hash = "sha256:9496b91bbe40ed01d341dc8f6ff0492d7f546e80f1a862b00ec5bc9045fa3324", size = 14340752, upload-time = "2025-09-15T19:38:35.659Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/30/75fdc75933d3bc1c8dd7fbaee771438328b518936906b411075b1eacac93/botocore-1.40.36.tar.gz", hash = "sha256:93386a8dc54173267ddfc6cd8636c9171e021f7c032aa1df3af7de816e3df616", size = 14349583, upload-time = "2025-09-22T19:26:05.957Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/42/98/0f6cfbc627a87d84cfc66ceb7d9b71d694313a32cddbe415b9f298c9e50b/botocore-1.40.31-py3-none-any.whl", hash = "sha256:4033a00f8c6a4b5c3acb30af9283963123917227a437e5fc165189d07bd3cf8a", size = 14013342, upload-time = "2025-09-15T19:38:32.098Z" }, + { url = "https://files.pythonhosted.org/packages/d8/51/95c0324ac20b5bbafad4c89dd610c8e0dd6cbadbb2c8ca66dc95ccde98b8/botocore-1.40.36-py3-none-any.whl", hash = "sha256:d6edf75875e4013cb7078875a1d6c289afb4cc6675d99d80700c692d8d8e0b72", size = 14020478, upload-time = "2025-09-22T19:26:02.054Z" }, ] [[package]] @@ -100,28 +91,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, - { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, - { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, - { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, - { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, - { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, - { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, - { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, - { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, - { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, - { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, - { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, - { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, - { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, ] [[package]] @@ -141,17 +110,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, - { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, - { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, - { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, - { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, - { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, - { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, - { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, - { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, - { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, - { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, ] @@ -183,37 +141,43 @@ wheels = [ [[package]] name = "cryptography" -version = "45.0.7" +version = "46.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/35/c495bffc2056f2dadb32434f1feedd79abde2a7f8363e1974afa9c33c7e2/cryptography-45.0.7.tar.gz", hash = "sha256:4b1654dfc64ea479c242508eb8c724044f1e964a47d1d1cacc5132292d851971", size = 744980, upload-time = "2025-09-01T11:15:03.146Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/91/925c0ac74362172ae4516000fe877912e33b5983df735ff290c653de4913/cryptography-45.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3be4f21c6245930688bd9e162829480de027f8bf962ede33d4f8ba7d67a00cee", size = 7041105, upload-time = "2025-09-01T11:13:59.684Z" }, - { url = "https://files.pythonhosted.org/packages/fc/63/43641c5acce3a6105cf8bd5baeceeb1846bb63067d26dae3e5db59f1513a/cryptography-45.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67285f8a611b0ebc0857ced2081e30302909f571a46bfa7a3cc0ad303fe015c6", size = 4205799, upload-time = "2025-09-01T11:14:02.517Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/c238dd9107f10bfde09a4d1c52fd38828b1aa353ced11f358b5dd2507d24/cryptography-45.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:577470e39e60a6cd7780793202e63536026d9b8641de011ed9d8174da9ca5339", size = 4430504, upload-time = "2025-09-01T11:14:04.522Z" }, - { url = "https://files.pythonhosted.org/packages/62/62/24203e7cbcc9bd7c94739428cd30680b18ae6b18377ae66075c8e4771b1b/cryptography-45.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4bd3e5c4b9682bc112d634f2c6ccc6736ed3635fc3319ac2bb11d768cc5a00d8", size = 4209542, upload-time = "2025-09-01T11:14:06.309Z" }, - { url = "https://files.pythonhosted.org/packages/cd/e3/e7de4771a08620eef2389b86cd87a2c50326827dea5528feb70595439ce4/cryptography-45.0.7-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:465ccac9d70115cd4de7186e60cfe989de73f7bb23e8a7aa45af18f7412e75bf", size = 3889244, upload-time = "2025-09-01T11:14:08.152Z" }, - { url = "https://files.pythonhosted.org/packages/96/b8/bca71059e79a0bb2f8e4ec61d9c205fbe97876318566cde3b5092529faa9/cryptography-45.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:16ede8a4f7929b4b7ff3642eba2bf79aa1d71f24ab6ee443935c0d269b6bc513", size = 4461975, upload-time = "2025-09-01T11:14:09.755Z" }, - { url = "https://files.pythonhosted.org/packages/58/67/3f5b26937fe1218c40e95ef4ff8d23c8dc05aa950d54200cc7ea5fb58d28/cryptography-45.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8978132287a9d3ad6b54fcd1e08548033cc09dc6aacacb6c004c73c3eb5d3ac3", size = 4209082, upload-time = "2025-09-01T11:14:11.229Z" }, - { url = "https://files.pythonhosted.org/packages/0e/e4/b3e68a4ac363406a56cf7b741eeb80d05284d8c60ee1a55cdc7587e2a553/cryptography-45.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b6a0e535baec27b528cb07a119f321ac024592388c5681a5ced167ae98e9fff3", size = 4460397, upload-time = "2025-09-01T11:14:12.924Z" }, - { url = "https://files.pythonhosted.org/packages/22/49/2c93f3cd4e3efc8cb22b02678c1fad691cff9dd71bb889e030d100acbfe0/cryptography-45.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a24ee598d10befaec178efdff6054bc4d7e883f615bfbcd08126a0f4931c83a6", size = 4337244, upload-time = "2025-09-01T11:14:14.431Z" }, - { url = "https://files.pythonhosted.org/packages/04/19/030f400de0bccccc09aa262706d90f2ec23d56bc4eb4f4e8268d0ddf3fb8/cryptography-45.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa26fa54c0a9384c27fcdc905a2fb7d60ac6e47d14bc2692145f2b3b1e2cfdbd", size = 4568862, upload-time = "2025-09-01T11:14:16.185Z" }, - { url = "https://files.pythonhosted.org/packages/29/56/3034a3a353efa65116fa20eb3c990a8c9f0d3db4085429040a7eef9ada5f/cryptography-45.0.7-cp311-abi3-win32.whl", hash = "sha256:bef32a5e327bd8e5af915d3416ffefdbe65ed975b646b3805be81b23580b57b8", size = 2936578, upload-time = "2025-09-01T11:14:17.638Z" }, - { url = "https://files.pythonhosted.org/packages/b3/61/0ab90f421c6194705a99d0fa9f6ee2045d916e4455fdbb095a9c2c9a520f/cryptography-45.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:3808e6b2e5f0b46d981c24d79648e5c25c35e59902ea4391a0dcb3e667bf7443", size = 3405400, upload-time = "2025-09-01T11:14:18.958Z" }, - { url = "https://files.pythonhosted.org/packages/63/e8/c436233ddf19c5f15b25ace33979a9dd2e7aa1a59209a0ee8554179f1cc0/cryptography-45.0.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bfb4c801f65dd61cedfc61a83732327fafbac55a47282e6f26f073ca7a41c3b2", size = 7021824, upload-time = "2025-09-01T11:14:20.954Z" }, - { url = "https://files.pythonhosted.org/packages/bc/4c/8f57f2500d0ccd2675c5d0cc462095adf3faa8c52294ba085c036befb901/cryptography-45.0.7-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:81823935e2f8d476707e85a78a405953a03ef7b7b4f55f93f7c2d9680e5e0691", size = 4202233, upload-time = "2025-09-01T11:14:22.454Z" }, - { url = "https://files.pythonhosted.org/packages/eb/ac/59b7790b4ccaed739fc44775ce4645c9b8ce54cbec53edf16c74fd80cb2b/cryptography-45.0.7-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3994c809c17fc570c2af12c9b840d7cea85a9fd3e5c0e0491f4fa3c029216d59", size = 4423075, upload-time = "2025-09-01T11:14:24.287Z" }, - { url = "https://files.pythonhosted.org/packages/b8/56/d4f07ea21434bf891faa088a6ac15d6d98093a66e75e30ad08e88aa2b9ba/cryptography-45.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dad43797959a74103cb59c5dac71409f9c27d34c8a05921341fb64ea8ccb1dd4", size = 4204517, upload-time = "2025-09-01T11:14:25.679Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ac/924a723299848b4c741c1059752c7cfe09473b6fd77d2920398fc26bfb53/cryptography-45.0.7-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ce7a453385e4c4693985b4a4a3533e041558851eae061a58a5405363b098fcd3", size = 3882893, upload-time = "2025-09-01T11:14:27.1Z" }, - { url = "https://files.pythonhosted.org/packages/83/dc/4dab2ff0a871cc2d81d3ae6d780991c0192b259c35e4d83fe1de18b20c70/cryptography-45.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b04f85ac3a90c227b6e5890acb0edbaf3140938dbecf07bff618bf3638578cf1", size = 4450132, upload-time = "2025-09-01T11:14:28.58Z" }, - { url = "https://files.pythonhosted.org/packages/12/dd/b2882b65db8fc944585d7fb00d67cf84a9cef4e77d9ba8f69082e911d0de/cryptography-45.0.7-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:48c41a44ef8b8c2e80ca4527ee81daa4c527df3ecbc9423c41a420a9559d0e27", size = 4204086, upload-time = "2025-09-01T11:14:30.572Z" }, - { url = "https://files.pythonhosted.org/packages/5d/fa/1d5745d878048699b8eb87c984d4ccc5da4f5008dfd3ad7a94040caca23a/cryptography-45.0.7-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f3df7b3d0f91b88b2106031fd995802a2e9ae13e02c36c1fc075b43f420f3a17", size = 4449383, upload-time = "2025-09-01T11:14:32.046Z" }, - { url = "https://files.pythonhosted.org/packages/36/8b/fc61f87931bc030598e1876c45b936867bb72777eac693e905ab89832670/cryptography-45.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd342f085542f6eb894ca00ef70236ea46070c8a13824c6bde0dfdcd36065b9b", size = 4332186, upload-time = "2025-09-01T11:14:33.95Z" }, - { url = "https://files.pythonhosted.org/packages/0b/11/09700ddad7443ccb11d674efdbe9a832b4455dc1f16566d9bd3834922ce5/cryptography-45.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1993a1bb7e4eccfb922b6cd414f072e08ff5816702a0bdb8941c247a6b1b287c", size = 4561639, upload-time = "2025-09-01T11:14:35.343Z" }, - { url = "https://files.pythonhosted.org/packages/71/ed/8f4c1337e9d3b94d8e50ae0b08ad0304a5709d483bfcadfcc77a23dbcb52/cryptography-45.0.7-cp37-abi3-win32.whl", hash = "sha256:18fcf70f243fe07252dcb1b268a687f2358025ce32f9f88028ca5c364b123ef5", size = 2926552, upload-time = "2025-09-01T11:14:36.929Z" }, - { url = "https://files.pythonhosted.org/packages/bc/ff/026513ecad58dacd45d1d24ebe52b852165a26e287177de1d545325c0c25/cryptography-45.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:7285a89df4900ed3bfaad5679b1e668cb4b38a8de1ccbfc84b05f34512da0a90", size = 3392742, upload-time = "2025-09-01T11:14:38.368Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/a9/62/e3664e6ffd7743e1694b244dde70b43a394f6f7fbcacf7014a8ff5197c73/cryptography-46.0.1.tar.gz", hash = "sha256:ed570874e88f213437f5cf758f9ef26cbfc3f336d889b1e592ee11283bb8d1c7", size = 749198, upload-time = "2025-09-17T00:10:35.797Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/8c/44ee01267ec01e26e43ebfdae3f120ec2312aa72fa4c0507ebe41a26739f/cryptography-46.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:1cd6d50c1a8b79af1a6f703709d8973845f677c8e97b1268f5ff323d38ce8475", size = 7285044, upload-time = "2025-09-17T00:08:36.807Z" }, + { url = "https://files.pythonhosted.org/packages/22/59/9ae689a25047e0601adfcb159ec4f83c0b4149fdb5c3030cc94cd218141d/cryptography-46.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0ff483716be32690c14636e54a1f6e2e1b7bf8e22ca50b989f88fa1b2d287080", size = 4308182, upload-time = "2025-09-17T00:08:39.388Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/ca6cc9df7118f2fcd142c76b1da0f14340d77518c05b1ebfbbabca6b9e7d/cryptography-46.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9873bf7c1f2a6330bdfe8621e7ce64b725784f9f0c3a6a55c3047af5849f920e", size = 4572393, upload-time = "2025-09-17T00:08:41.663Z" }, + { url = "https://files.pythonhosted.org/packages/7f/a3/0f5296f63815d8e985922b05c31f77ce44787b3127a67c0b7f70f115c45f/cryptography-46.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0dfb7c88d4462a0cfdd0d87a3c245a7bc3feb59de101f6ff88194f740f72eda6", size = 4308400, upload-time = "2025-09-17T00:08:43.559Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8c/74fcda3e4e01be1d32775d5b4dd841acaac3c1b8fa4d0774c7ac8d52463d/cryptography-46.0.1-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e22801b61613ebdebf7deb18b507919e107547a1d39a3b57f5f855032dd7cfb8", size = 4015786, upload-time = "2025-09-17T00:08:45.758Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b8/85d23287baeef273b0834481a3dd55bbed3a53587e3b8d9f0898235b8f91/cryptography-46.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:757af4f6341ce7a1e47c326ca2a81f41d236070217e5fbbad61bbfe299d55d28", size = 4982606, upload-time = "2025-09-17T00:08:47.602Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d3/de61ad5b52433b389afca0bc70f02a7a1f074651221f599ce368da0fe437/cryptography-46.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f7a24ea78de345cfa7f6a8d3bde8b242c7fac27f2bd78fa23474ca38dfaeeab9", size = 4604234, upload-time = "2025-09-17T00:08:49.879Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1f/dbd4d6570d84748439237a7478d124ee0134bf166ad129267b7ed8ea6d22/cryptography-46.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e8776dac9e660c22241b6587fae51a67b4b0147daa4d176b172c3ff768ad736", size = 4307669, upload-time = "2025-09-17T00:08:52.321Z" }, + { url = "https://files.pythonhosted.org/packages/ec/fd/ca0a14ce7f0bfe92fa727aacaf2217eb25eb7e4ed513b14d8e03b26e63ed/cryptography-46.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9f40642a140c0c8649987027867242b801486865277cbabc8c6059ddef16dc8b", size = 4947579, upload-time = "2025-09-17T00:08:54.697Z" }, + { url = "https://files.pythonhosted.org/packages/89/6b/09c30543bb93401f6f88fce556b3bdbb21e55ae14912c04b7bf355f5f96c/cryptography-46.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:449ef2b321bec7d97ef2c944173275ebdab78f3abdd005400cc409e27cd159ab", size = 4603669, upload-time = "2025-09-17T00:08:57.16Z" }, + { url = "https://files.pythonhosted.org/packages/23/9a/38cb01cb09ce0adceda9fc627c9cf98eb890fc8d50cacbe79b011df20f8a/cryptography-46.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2dd339ba3345b908fa3141ddba4025568fa6fd398eabce3ef72a29ac2d73ad75", size = 4435828, upload-time = "2025-09-17T00:08:59.606Z" }, + { url = "https://files.pythonhosted.org/packages/0f/53/435b5c36a78d06ae0bef96d666209b0ecd8f8181bfe4dda46536705df59e/cryptography-46.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7411c910fb2a412053cf33cfad0153ee20d27e256c6c3f14d7d7d1d9fec59fd5", size = 4709553, upload-time = "2025-09-17T00:09:01.832Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c4/0da6e55595d9b9cd3b6eb5dc22f3a07ded7f116a3ea72629cab595abb804/cryptography-46.0.1-cp311-abi3-win32.whl", hash = "sha256:cbb8e769d4cac884bb28e3ff620ef1001b75588a5c83c9c9f1fdc9afbe7f29b0", size = 3058327, upload-time = "2025-09-17T00:09:03.726Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/cd29a35e0d6e78a0ee61793564c8cff0929c38391cb0de27627bdc7525aa/cryptography-46.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:92e8cfe8bd7dd86eac0a677499894862cd5cc2fd74de917daa881d00871ac8e7", size = 3523893, upload-time = "2025-09-17T00:09:06.272Z" }, + { url = "https://files.pythonhosted.org/packages/f2/dd/eea390f3e78432bc3d2f53952375f8b37cb4d37783e626faa6a51e751719/cryptography-46.0.1-cp311-abi3-win_arm64.whl", hash = "sha256:db5597a4c7353b2e5fb05a8e6cb74b56a4658a2b7bf3cb6b1821ae7e7fd6eaa0", size = 2932145, upload-time = "2025-09-17T00:09:08.568Z" }, + { url = "https://files.pythonhosted.org/packages/98/e5/fbd632385542a3311915976f88e0dfcf09e62a3fc0aff86fb6762162a24d/cryptography-46.0.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d84c40bdb8674c29fa192373498b6cb1e84f882889d21a471b45d1f868d8d44b", size = 7255677, upload-time = "2025-09-17T00:09:42.407Z" }, + { url = "https://files.pythonhosted.org/packages/56/3e/13ce6eab9ad6eba1b15a7bd476f005a4c1b3f299f4c2f32b22408b0edccf/cryptography-46.0.1-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ed64e5083fa806709e74fc5ea067dfef9090e5b7a2320a49be3c9df3583a2d8", size = 4301110, upload-time = "2025-09-17T00:09:45.614Z" }, + { url = "https://files.pythonhosted.org/packages/a2/67/65dc233c1ddd688073cf7b136b06ff4b84bf517ba5529607c9d79720fc67/cryptography-46.0.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:341fb7a26bc9d6093c1b124b9f13acc283d2d51da440b98b55ab3f79f2522ead", size = 4562369, upload-time = "2025-09-17T00:09:47.601Z" }, + { url = "https://files.pythonhosted.org/packages/17/db/d64ae4c6f4e98c3dac5bf35dd4d103f4c7c345703e43560113e5e8e31b2b/cryptography-46.0.1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6ef1488967e729948d424d09c94753d0167ce59afba8d0f6c07a22b629c557b2", size = 4302126, upload-time = "2025-09-17T00:09:49.335Z" }, + { url = "https://files.pythonhosted.org/packages/3d/19/5f1eea17d4805ebdc2e685b7b02800c4f63f3dd46cfa8d4c18373fea46c8/cryptography-46.0.1-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7823bc7cdf0b747ecfb096d004cc41573c2f5c7e3a29861603a2871b43d3ef32", size = 4009431, upload-time = "2025-09-17T00:09:51.239Z" }, + { url = "https://files.pythonhosted.org/packages/81/b5/229ba6088fe7abccbfe4c5edb96c7a5ad547fac5fdd0d40aa6ea540b2985/cryptography-46.0.1-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:f736ab8036796f5a119ff8211deda416f8c15ce03776db704a7a4e17381cb2ef", size = 4980739, upload-time = "2025-09-17T00:09:54.181Z" }, + { url = "https://files.pythonhosted.org/packages/3a/9c/50aa38907b201e74bc43c572f9603fa82b58e831bd13c245613a23cff736/cryptography-46.0.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e46710a240a41d594953012213ea8ca398cd2448fbc5d0f1be8160b5511104a0", size = 4592289, upload-time = "2025-09-17T00:09:56.731Z" }, + { url = "https://files.pythonhosted.org/packages/5a/33/229858f8a5bb22f82468bb285e9f4c44a31978d5f5830bb4ea1cf8a4e454/cryptography-46.0.1-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:84ef1f145de5aee82ea2447224dc23f065ff4cc5791bb3b506615957a6ba8128", size = 4301815, upload-time = "2025-09-17T00:09:58.548Z" }, + { url = "https://files.pythonhosted.org/packages/52/cb/b76b2c87fbd6ed4a231884bea3ce073406ba8e2dae9defad910d33cbf408/cryptography-46.0.1-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9394c7d5a7565ac5f7d9ba38b2617448eba384d7b107b262d63890079fad77ca", size = 4943251, upload-time = "2025-09-17T00:10:00.475Z" }, + { url = "https://files.pythonhosted.org/packages/94/0f/f66125ecf88e4cb5b8017ff43f3a87ede2d064cb54a1c5893f9da9d65093/cryptography-46.0.1-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ed957044e368ed295257ae3d212b95456bd9756df490e1ac4538857f67531fcc", size = 4591247, upload-time = "2025-09-17T00:10:02.874Z" }, + { url = "https://files.pythonhosted.org/packages/f6/22/9f3134ae436b63b463cfdf0ff506a0570da6873adb4bf8c19b8a5b4bac64/cryptography-46.0.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f7de12fa0eee6234de9a9ce0ffcfa6ce97361db7a50b09b65c63ac58e5f22fc7", size = 4428534, upload-time = "2025-09-17T00:10:04.994Z" }, + { url = "https://files.pythonhosted.org/packages/89/39/e6042bcb2638650b0005c752c38ea830cbfbcbb1830e4d64d530000aa8dc/cryptography-46.0.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7fab1187b6c6b2f11a326f33b036f7168f5b996aedd0c059f9738915e4e8f53a", size = 4699541, upload-time = "2025-09-17T00:10:06.925Z" }, + { url = "https://files.pythonhosted.org/packages/68/46/753d457492d15458c7b5a653fc9a84a1c9c7a83af6ebdc94c3fc373ca6e8/cryptography-46.0.1-cp38-abi3-win32.whl", hash = "sha256:45f790934ac1018adeba46a0f7289b2b8fe76ba774a88c7f1922213a56c98bc1", size = 3043779, upload-time = "2025-09-17T00:10:08.951Z" }, + { url = "https://files.pythonhosted.org/packages/2f/50/b6f3b540c2f6ee712feeb5fa780bb11fad76634e71334718568e7695cb55/cryptography-46.0.1-cp38-abi3-win_amd64.whl", hash = "sha256:7176a5ab56fac98d706921f6416a05e5aff7df0e4b91516f450f8627cda22af3", size = 3517226, upload-time = "2025-09-17T00:10:10.769Z" }, + { url = "https://files.pythonhosted.org/packages/ff/e8/77d17d00981cdd27cc493e81e1749a0b8bbfb843780dbd841e30d7f50743/cryptography-46.0.1-cp38-abi3-win_arm64.whl", hash = "sha256:efc9e51c3e595267ff84adf56e9b357db89ab2279d7e375ffcaf8f678606f3d9", size = 2923149, upload-time = "2025-09-17T00:10:13.236Z" }, ] [[package]] @@ -365,10 +329,9 @@ wheels = [ [[package]] name = "hip-3-pusher" -version = "0.1.3" +version = "0.1.4" source = { virtual = "." } dependencies = [ - { name = "asn1crypto" }, { name = "boto3" }, { name = "cryptography" }, { name = "hyperliquid-python-sdk" }, @@ -376,22 +339,19 @@ dependencies = [ { name = "opentelemetry-exporter-prometheus" }, { name = "opentelemetry-sdk" }, { name = "prometheus-client" }, - { name = "toml" }, { name = "websockets" }, ] [package.metadata] requires-dist = [ - { name = "asn1crypto", specifier = ">=1.5.1" }, - { name = "boto3", specifier = ">=1.40.31" }, - { name = "cryptography", specifier = ">=45.0.7" }, - { name = "hyperliquid-python-sdk", specifier = ">=0.19.0" }, - { name = "loguru", specifier = ">=0.7.3" }, - { name = "opentelemetry-exporter-prometheus", specifier = ">=0.58b0" }, - { name = "opentelemetry-sdk", specifier = ">=1.37.0" }, - { name = "prometheus-client", specifier = ">=0.23.1" }, - { name = "toml", specifier = ">=0.10.2" }, - { name = "websockets", specifier = ">=15.0.1" }, + { name = "boto3", specifier = "~=1.40.34" }, + { name = "cryptography", specifier = "~=46.0.1" }, + { name = "hyperliquid-python-sdk", specifier = "~=0.19.0" }, + { name = "loguru", specifier = "~=0.7.3" }, + { name = "opentelemetry-exporter-prometheus", specifier = "~=0.58b0" }, + { name = "opentelemetry-sdk", specifier = "~=1.37.0" }, + { name = "prometheus-client", specifier = "~=0.23.1" }, + { name = "websockets", specifier = "~=15.0.1" }, ] [[package]] @@ -660,20 +620,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/36/674672f3fdead107565a2499f3007788b878188acec6d42bc141c5366c2c/regex-2025.9.1-cp313-cp313-win32.whl", hash = "sha256:3b9a62107a7441b81ca98261808fed30ae36ba06c8b7ee435308806bd53c1ed8", size = 264508, upload-time = "2025-09-01T22:09:16.193Z" }, { url = "https://files.pythonhosted.org/packages/83/ad/931134539515eb64ce36c24457a98b83c1b2e2d45adf3254b94df3735a76/regex-2025.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:b38afecc10c177eb34cfae68d669d5161880849ba70c05cbfbe409f08cc939d7", size = 275469, upload-time = "2025-09-01T22:09:17.462Z" }, { url = "https://files.pythonhosted.org/packages/24/8c/96d34e61c0e4e9248836bf86d69cb224fd222f270fa9045b24e218b65604/regex-2025.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:ec329890ad5e7ed9fc292858554d28d58d56bf62cf964faf0aa57964b21155a0", size = 268586, upload-time = "2025-09-01T22:09:18.948Z" }, - { url = "https://files.pythonhosted.org/packages/21/b1/453cbea5323b049181ec6344a803777914074b9726c9c5dc76749966d12d/regex-2025.9.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:72fb7a016467d364546f22b5ae86c45680a4e0de6b2a6f67441d22172ff641f1", size = 486111, upload-time = "2025-09-01T22:09:20.734Z" }, - { url = "https://files.pythonhosted.org/packages/f6/0e/92577f197bd2f7652c5e2857f399936c1876978474ecc5b068c6d8a79c86/regex-2025.9.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c9527fa74eba53f98ad86be2ba003b3ebe97e94b6eb2b916b31b5f055622ef03", size = 289520, upload-time = "2025-09-01T22:09:22.249Z" }, - { url = "https://files.pythonhosted.org/packages/af/c6/b472398116cca7ea5a6c4d5ccd0fc543f7fd2492cb0c48d2852a11972f73/regex-2025.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c905d925d194c83a63f92422af7544ec188301451b292c8b487f0543726107ca", size = 287215, upload-time = "2025-09-01T22:09:23.657Z" }, - { url = "https://files.pythonhosted.org/packages/cf/11/f12ecb0cf9ca792a32bb92f758589a84149017467a544f2f6bfb45c0356d/regex-2025.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74df7c74a63adcad314426b1f4ea6054a5ab25d05b0244f0c07ff9ce640fa597", size = 797855, upload-time = "2025-09-01T22:09:25.197Z" }, - { url = "https://files.pythonhosted.org/packages/46/88/bbb848f719a540fb5997e71310f16f0b33a92c5d4b4d72d4311487fff2a3/regex-2025.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4f6e935e98ea48c7a2e8be44494de337b57a204470e7f9c9c42f912c414cd6f5", size = 863363, upload-time = "2025-09-01T22:09:26.705Z" }, - { url = "https://files.pythonhosted.org/packages/54/a9/2321eb3e2838f575a78d48e03c1e83ea61bd08b74b7ebbdeca8abc50fc25/regex-2025.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4a62d033cd9ebefc7c5e466731a508dfabee827d80b13f455de68a50d3c2543d", size = 910202, upload-time = "2025-09-01T22:09:28.906Z" }, - { url = "https://files.pythonhosted.org/packages/33/07/d1d70835d7d11b7e126181f316f7213c4572ecf5c5c97bdbb969fb1f38a2/regex-2025.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef971ebf2b93bdc88d8337238be4dfb851cc97ed6808eb04870ef67589415171", size = 801808, upload-time = "2025-09-01T22:09:30.733Z" }, - { url = "https://files.pythonhosted.org/packages/13/d1/29e4d1bed514ef2bf3a4ead3cb8bb88ca8af94130239a4e68aa765c35b1c/regex-2025.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d936a1db208bdca0eca1f2bb2c1ba1d8370b226785c1e6db76e32a228ffd0ad5", size = 786824, upload-time = "2025-09-01T22:09:32.61Z" }, - { url = "https://files.pythonhosted.org/packages/33/27/20d8ccb1bee460faaa851e6e7cc4cfe852a42b70caa1dca22721ba19f02f/regex-2025.9.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:7e786d9e4469698fc63815b8de08a89165a0aa851720eb99f5e0ea9d51dd2b6a", size = 857406, upload-time = "2025-09-01T22:09:34.117Z" }, - { url = "https://files.pythonhosted.org/packages/74/fe/60c6132262dc36430d51e0c46c49927d113d3a38c1aba6a26c7744c84cf3/regex-2025.9.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6b81d7dbc5466ad2c57ce3a0ddb717858fe1a29535c8866f8514d785fdb9fc5b", size = 848593, upload-time = "2025-09-01T22:09:35.598Z" }, - { url = "https://files.pythonhosted.org/packages/cc/ae/2d4ff915622fabbef1af28387bf71e7f2f4944a348b8460d061e85e29bf0/regex-2025.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cd4890e184a6feb0ef195338a6ce68906a8903a0f2eb7e0ab727dbc0a3156273", size = 787951, upload-time = "2025-09-01T22:09:37.139Z" }, - { url = "https://files.pythonhosted.org/packages/85/37/dc127703a9e715a284cc2f7dbdd8a9776fd813c85c126eddbcbdd1ca5fec/regex-2025.9.1-cp314-cp314-win32.whl", hash = "sha256:34679a86230e46164c9e0396b56cab13c0505972343880b9e705083cc5b8ec86", size = 269833, upload-time = "2025-09-01T22:09:39.245Z" }, - { url = "https://files.pythonhosted.org/packages/83/bf/4bed4d3d0570e16771defd5f8f15f7ea2311edcbe91077436d6908956c4a/regex-2025.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:a1196e530a6bfa5f4bde029ac5b0295a6ecfaaffbfffede4bbaf4061d9455b70", size = 278742, upload-time = "2025-09-01T22:09:40.651Z" }, - { url = "https://files.pythonhosted.org/packages/cf/3e/7d7ac6fd085023312421e0d69dfabdfb28e116e513fadbe9afe710c01893/regex-2025.9.1-cp314-cp314-win_arm64.whl", hash = "sha256:f46d525934871ea772930e997d577d48c6983e50f206ff7b66d4ac5f8941e993", size = 271860, upload-time = "2025-09-01T22:09:42.413Z" }, ] [[package]] @@ -724,15 +670,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] -[[package]] -name = "toml" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, -] - [[package]] name = "toolz" version = "1.0.0"