feat: add adaptive fee

This commit is contained in:
2026-05-13 14:22:43 +03:00
parent 4c702b6260
commit bb89aaeee5
4 changed files with 82 additions and 13 deletions

View File

@@ -1,10 +1,35 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime,timezone
from decimal import Decimal,ROUND_UP
from src.application.contracts import ICache,ILogger
from src.application.domain.exceptions import ServiceUnavailableException
from src.infrastructure.config import settings
from datetime import datetime, timezone
from decimal import Decimal, ROUND_UP
from src.application.contracts import ICache, ILogger
from src.application.domain.exceptions import OrderTotalOutOfRangeException, ServiceUnavailableException
_FEE_TIERS: tuple[tuple[Decimal, Decimal, Decimal, bool, bool], ...] = (
(Decimal('0.08'), Decimal('5000'), Decimal('30000'), True, True),
(Decimal('0.06'), Decimal('30000'), Decimal('100000'), False, True),
(Decimal('0.04'), Decimal('100000'), Decimal('600000'), False, True),
)
def _total_in_bracket(
total: Decimal,
lo: Decimal,
hi: Decimal,
*,
lo_inclusive: bool,
hi_inclusive: bool,
) -> bool:
if lo_inclusive:
ok_lo = total >= lo
else:
ok_lo = total > lo
if hi_inclusive:
ok_hi = total <= hi
else:
ok_hi = total < hi
return ok_lo and ok_hi
@dataclass(slots=True)
@@ -25,8 +50,8 @@ class PaymentQuoteService:
async def get_quote(self, usdt_amount: Decimal) -> PaymentQuote:
rate_raw = await self._remote_cache.hget('tradex:rub:rate','value')
gas_raw = await self._remote_cache.hget('gwei:eth:last','normal_rub')
rate_raw = await self._remote_cache.hget('tradex:rub:rate', 'value')
gas_raw = await self._remote_cache.hget('gwei:eth:last', 'normal_rub')
self._logger.info(f'Actual market values: rate={rate_raw}, gas={gas_raw}')
if rate_raw is None:
@@ -39,8 +64,41 @@ class PaymentQuoteService:
gas_fee = Decimal(gas_raw).quantize(Decimal('0.00'), rounding=ROUND_UP)
usdt_exchange_rate = Decimal(rate_raw).quantize(Decimal('0.00'), rounding=ROUND_UP)
service_fee = (usdt_amount * usdt_exchange_rate * settings.PAYMENT_SERVICE_FEE_RATE).quantize(Decimal('0.01'))
total_price = (usdt_amount * usdt_exchange_rate + service_fee + gas_fee).quantize(Decimal('0.01'))
base_rub = usdt_amount * usdt_exchange_rate
chosen_rate: Decimal | None = None
service_fee: Decimal | None = None
total_price: Decimal | None = None
for fee_rate, lo, hi, li, ri in _FEE_TIERS:
sf = (base_rub * fee_rate).quantize(Decimal('0.01'))
tp = (base_rub + sf + gas_fee).quantize(Decimal('0.01'))
if _total_in_bracket(tp, lo, hi, lo_inclusive=li, hi_inclusive=ri):
chosen_rate = fee_rate
service_fee = sf
total_price = tp
break
if chosen_rate is None or service_fee is None or total_price is None:
total_if_lowest_fee = (
base_rub
+ (base_rub * Decimal('0.04')).quantize(Decimal('0.01'))
+ gas_fee
).quantize(Decimal('0.01'))
if total_if_lowest_fee > Decimal('600000'):
raise OrderTotalOutOfRangeException(
message='Order total exceeds maximum allowed amount',
)
total_if_highest_fee = (
base_rub
+ (base_rub * Decimal('0.08')).quantize(Decimal('0.01'))
+ gas_fee
).quantize(Decimal('0.01'))
if total_if_highest_fee < Decimal('5000'):
raise OrderTotalOutOfRangeException(
message='Order total is below minimum allowed amount',
)
raise OrderTotalOutOfRangeException()
return PaymentQuote(
usdt_amount=usdt_amount,
@@ -48,6 +106,6 @@ class PaymentQuoteService:
gas_fee=gas_fee,
service_fee=service_fee,
total_price=total_price,
service_fee_rate=settings.PAYMENT_SERVICE_FEE_RATE,
service_fee_rate=chosen_rate,
created_at=datetime.now(timezone.utc),
)