def calculate_token_eth_price( token_address: ChecksumAddress, redis_key: str, force_recalculation: bool = False) -> Optional[float]: """ Do price calculation for token in an async way and store it on redis :param token_address: Token address :param redis_key: Redis key for token price :param force_recalculation: Force a new calculation even if an old one is on cache :return: token price (in ether) when calculated """ redis = get_redis() key_was_set = redis.set(redis_key, 0, ex=50, nx=True) if key_was_set or force_recalculation: price_service = PriceServiceProvider() eth_price = price_service.get_token_eth_value(token_address) if not eth_price: # Try usd oracles usd_price = price_service.get_token_usd_price(token_address) if usd_price: eth_usd_price = price_service.get_eth_usd_price() eth_price = usd_price / eth_usd_price redis_expiration_time = 60 * 30 # Expire in 30 minutes redis.setex(redis_key, redis_expiration_time, eth_price) if eth_price and not getattr(settings, 'CELERY_ALWAYS_EAGER', False): # Recalculate price before cache expires and prevents recursion checking Celery Eager property calculate_token_eth_price.apply_async( (token_address, redis_key), {'force_recalculation': True}, countdown=redis_expiration_time - 300) return eth_price else: float(redis.get(redis_key))
def get_token_info_from_blockchain(token_address: ChecksumAddress) -> bool: """ Retrieve token information from blockchain :param token_address: :return: `True` if found, `False` otherwise """ redis = get_redis() key = f'token-task:{token_address}' if result := redis.get(key): return bool(int(result))
def calculate_token_eth_price_task( token_address: ChecksumAddress, redis_key: str, force_recalculation: bool = False) -> Optional[EthValueWithTimestamp]: """ Do price calculation for token in an async way and store it with its timestamp on redis :param token_address: Token address :param redis_key: Redis key for token price :param force_recalculation: Force a new calculation even if an old one is on cache :return: token price (in ether) when calculated """ redis_expiration_time = 60 * 30 # Expire in 30 minutes redis = get_redis() now = timezone.now() current_timestamp = int(now.timestamp()) key_was_set = redis.set(redis_key, f'0:{current_timestamp}', ex=60 * 15, nx=True) # Expire in 15 minutes if key_was_set or force_recalculation: price_service = PriceServiceProvider() eth_price = price_service.get_token_eth_value(token_address) if not eth_price: # Try usd oracles usd_price = price_service.get_token_usd_price(token_address) if usd_price: eth_usd_price = price_service.get_eth_usd_price() eth_price = usd_price / eth_usd_price if eth_price: eth_value_with_timestamp = EthValueWithTimestamp(eth_price, now) redis.setex(redis_key, redis_expiration_time, str(eth_value_with_timestamp)) if not getattr(settings, 'CELERY_ALWAYS_EAGER', False): # Recalculate price before cache expires and prevents recursion checking Celery Eager property calculate_token_eth_price_task.apply_async( (token_address, redis_key), {'force_recalculation': True}, countdown=redis_expiration_time - 300) else: logger.warning('Cannot calculate eth price for token=%s', token_address) return EthValueWithTimestamp(eth_price, now) else: return EthValueWithTimestamp.from_string(redis.get(redis_key).decode())
def __new__(cls): if not hasattr(cls, 'instance'): cls.instance = PriceService(EthereumClientProvider(), get_redis()) return cls.instance
def __init__(self, address: Optional[str], payload: Dict[str, Any]): self.redis = get_redis() self.address = address self.payload = payload self.redis_payload = self._get_redis_payload(address, payload)