from decimal import getcontext, Decimal
import random, os
from dotenv import load_dotenv
from aiogram_dialog.widgets.kbd import Button, Row, Group, Radio, ManagedRadio
from aiogram_dialog.widgets.input import TextInput, ManagedTextInput, MessageInput
from aiogram_dialog import Dialog, Window, ChatEvent, DialogManager
from aiogram_dialog.widgets.text import Format
from aiogram_dialog.widgets.kbd import Cancel
from aiogram_dialog.widgets.kbd import SwitchTo
from aiogram.types import CallbackQuery, Message
from aiogram.enums import ContentType
from fluentogram import TranslatorHub
from spl.token.instructions import get_associated_token_address
from solana.rpc.types import Pubkey
from bot.dialogs.i18n_widget import I18NFormat
from bot.states.states import Balance, Input
from database.repositories.user import UserRepository
from database.repositories.utils import UtilsRepository
from bot.utils.get_ton_course import get_ton_course
import bot.keyboards.inline as inline_kb
from config import TYPE_USAGE
load_dotenv()
def check_input_text(text: str):
if not text:
return
if not text.isdigit():
return
if int(text) < 1:
return
return True
def apply_suffix(base: str, suffix: str) -> str:
int_part, frac_part = base.split('.')
N = len(frac_part)
M = len(suffix)
new_frac = frac_part[:N - M] + suffix
return f"{int_part}.{new_frac}"
def generate_amount(usd_amount: float, rate: float, suffix: str, num_decimals: int = 9) -> str:
getcontext().prec = 18
ton_base = Decimal(usd_amount) / Decimal(rate)
base_str = f"{ton_base:.{num_decimals}f}"
result = apply_suffix(base_str, suffix)
return result
async def on_cancel_balance(callback: ChatEvent, widget: Button, manager: DialogManager):
state = manager.middleware_data.get('state')
await state.clear()
await callback.message.delete()
async def input_text_first(message: Message, widget: MessageInput, manager: DialogManager):
if not check_input_text(message.text):
return await manager.switch_to(state=Balance.input_not_format)
manager.dialog_data['sum'] = message.text
state = manager.middleware_data.get('state')
await state.clear()
await manager.switch_to(Balance.choose)
async def input_text_second(message: Message, widget: MessageInput, manager: DialogManager):
if not check_input_text(message.text):
return
manager.dialog_data['sum'] = message.text
state = manager.middleware_data.get('state')
await state.clear()
await manager.switch_to(Balance.choose)
async def on_click_add_balance(callback: ChatEvent, widget: Button, manager: DialogManager):
state = manager.middleware_data.get('state')
await state.set_state(Input.main)
await manager.switch_to(Balance.input)
async def on_click_ton_type(callback: ChatEvent, widget: Button, manager: DialogManager):
utils_repo: UtilsRepository = manager.middleware_data['utils_repo']
user_repo: UserRepository = manager.middleware_data['user_repo']
i18n = manager.middleware_data.get('i18n')
while True:
suffix = f"{random.randint(0, 9999):04d}"
if await utils_repo.check_payment_suffix(suffix):
break
try:
sum_usd = manager.dialog_data.get('sum')
ton_course = await get_ton_course(redis=manager.middleware_data['redis'])
generate_sum = generate_amount(usd_amount=float(sum_usd), rate=ton_course, suffix=suffix)
payment_id = await user_repo.add_payment(callback.from_user.id, amount=int(sum_usd), crypto_amount=generate_sum,
crypto_currency='TON', random_suffix=suffix)
await manager.done()
await callback.message.edit_text(i18n.get('text_payment_create', sum=generate_sum, wallet=os.getenv('TON_ADDRESS')),
reply_markup=inline_kb.check_payment(text=i18n.get('check_payment_kb'), payment_id=payment_id))
except Exception as e:
print(e)
return await callback.answer(text=i18n.get('error_create_payment'), show_alert=True)
async def on_click_sol_type(callback: ChatEvent, widget: Button, manager: DialogManager):
utils_repo: UtilsRepository = manager.middleware_data['utils_repo']
user_repo: UserRepository = manager.middleware_data['user_repo']
i18n = manager.middleware_data.get('i18n')
token = await utils_repo.get_token()
if not token:
return await callback.answer(text=i18n.get('error_get_token_price'), show_alert=True)
client_sol = manager.middleware_data['solana_client']
ata = get_associated_token_address(mint=Pubkey.from_string(os.getenv('MINT_TOKEN_ADDRESS')),
owner=Pubkey.from_string(os.getenv('ADDRESS_SOL')))
bal_info = await client_sol.get_token_account_balance(ata, commitment="confirmed")
decimals = bal_info.value.decimals
while True:
suffix = f"{random.randint(0, 9999):04d}"
if await utils_repo.check_payment_suffix(suffix):
break
try:
sum_usd = manager.dialog_data.get('sum')
generate_sum = generate_amount(usd_amount=float(sum_usd), rate=token.price_usd, suffix=suffix, num_decimals=decimals)
payment_id = await user_repo.add_payment(callback.from_user.id, amount=int(sum_usd), crypto_amount=generate_sum,
crypto_currency='SOL', random_suffix=suffix)
await manager.done()
await callback.message.edit_text(i18n.get('text_payment_create_sol', sum=generate_sum, wallet=os.getenv('ADDRESS_SOL'), token=os.getenv('MINT_TOKEN_ADDRESS')),
reply_markup=inline_kb.check_payment(text=i18n.get('check_payment_kb'), payment_id=payment_id))
except Exception as e:
print(e)
return await callback.answer(text=i18n.get('error_create_payment'), show_alert=True)
async def getter_balance(dialog_manager: DialogManager, **kwargs):
user = dialog_manager.middleware_data['user']
return {
'balance': round(user.balance_credits, 3),
'is_pay': True if TYPE_USAGE == 'pay' else False
}
dialog = Dialog(
Window(
I18NFormat('cmd_wallet_text') + Format(' {balance} credits'),
Button(
I18NFormat('add_balance_kb'),
id='choose_add_balance',
on_click=on_click_add_balance,
when='is_pay'
),
Cancel(I18NFormat('close_kb'), id='cancel_balance', on_click=on_cancel_balance),
state=Balance.main,
getter=getter_balance
),
Window(
I18NFormat('text_add_balance'),
MessageInput(
func=input_text_first,
content_types=[ContentType.ANY],
),
Cancel(I18NFormat('close_kb'), id='cancel_balance', on_click=on_cancel_balance),
state=Balance.input
),
Window(
I18NFormat('text_add_balance_error'),
MessageInput(
func=input_text_second,
content_types=[ContentType.ANY],
),
Cancel(I18NFormat('close_kb'), id='cancel_balance', on_click=on_cancel_balance),
state=Balance.input_not_format
),
Window(
I18NFormat('choose_type_pay_text'),
Group(
Button(
I18NFormat('ton_type_kb'),
id='ton_type',
on_click=on_click_ton_type
),
Button(
I18NFormat('sol_type_kb'),
id='sol_type',
on_click=on_click_sol_type
),
width=2
),
Cancel(I18NFormat('close_kb'), id='cancel_balance', on_click=on_cancel_balance),
state=Balance.choose
)
)