from __future__ import annotations from dataclasses import dataclass from decimal import Decimal,ROUND_DOWN,ROUND_UP from src.application.contracts import ICache,ILogger from src.application.domain.exceptions import OrderTotalOutOfRangeException,ServiceUnavailableException MIN_SBP_WITHDRAWAL_USDT: Decimal=Decimal('100') MAX_SBP_WITHDRAWAL_USDT: Decimal=Decimal('5000') _FEE_TIERS: tuple[tuple[Decimal,Decimal,Decimal],...]=( (Decimal('100'),Decimal('2000'),Decimal('0.08')), (Decimal('2000.01'),Decimal('4000'),Decimal('0.06')), (Decimal('4000.01'),Decimal('5000'),Decimal('0.04')), ) @dataclass(slots=True) class SbpWithdrawalQuote: usdt_amount: Decimal rub_amount: Decimal usdt_exchange_rate: Decimal service_fee_rate: Decimal service_fee_usdt: Decimal class SbpWithdrawalQuoteService: def __init__(self,*,remote_cache: ICache,logger: ILogger): self._remote_cache=remote_cache self._logger=logger async def _load_rate(self) -> Decimal: rate_raw=await self._remote_cache.hget('tradex:rub:rate','value') self._logger.info(f'Actual market value for SBP withdrawal: rate={rate_raw}') if rate_raw is None: raise ServiceUnavailableException(message='Exchange rate unavailable') return Decimal(rate_raw).quantize(Decimal('0.00'),rounding=ROUND_UP) @staticmethod def _fee_rate(usdt_amount: Decimal) -> Decimal: for lo,hi,rate in _FEE_TIERS: if lo<=usdt_amount<=hi: return rate raise OrderTotalOutOfRangeException(message='Withdrawal amount is out of range') async def get_quote(self,usdt_amount: Decimal) -> SbpWithdrawalQuote: if usdt_amountMAX_SBP_WITHDRAWAL_USDT: raise OrderTotalOutOfRangeException(message='Withdrawal amount exceeds maximum allowed amount') rate=await self._load_rate() fee_rate=self._fee_rate(usdt_amount) service_fee=(usdt_amount*fee_rate).quantize(Decimal('0.01')) payout_usdt=(usdt_amount-service_fee).quantize(Decimal('0.01')) rub_amount=(payout_usdt*rate).quantize(Decimal('1'),rounding=ROUND_DOWN) return SbpWithdrawalQuote( usdt_amount=usdt_amount, rub_amount=rub_amount, usdt_exchange_rate=rate, service_fee_rate=fee_rate, service_fee_usdt=service_fee, )