mirror of
https://github.com/vibe-existing/pyfragment.git
synced 2026-07-25 06:54:31 +00:00
120 lines
5.1 KiB
Python
120 lines
5.1 KiB
Python
import base64
|
|
import logging
|
|
import time
|
|
|
|
import httpx
|
|
from tonutils.client import TonapiClient
|
|
from tonutils.wallet import WalletV5R1
|
|
|
|
from app.core.config import Config
|
|
from app.utils import TransactionProcessor, WalletLinker, ApiClient, clean_decode
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class FragmentTon:
|
|
def __init__(self):
|
|
config_reader = Config()
|
|
self.config = config_reader.get_config()
|
|
|
|
self.headers = {
|
|
'accept': 'application/json, text/javascript, */*; q=0.01',
|
|
'accept-encoding': 'gzip, deflate, br, zstd',
|
|
'accept-language': 'en-US,en;q=0.9,uk;q=0.8,ru;q=0.7',
|
|
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
'cookie': self.config['cookies'],
|
|
'origin': 'https://fragment.com',
|
|
'referer': 'https://fragment.com/ads/topup',
|
|
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1',
|
|
'x-requested-with': 'XMLHttpRequest'
|
|
}
|
|
|
|
self.transaction_processor = TransactionProcessor(self.config, clean_decode)
|
|
self.wallet_linker = WalletLinker(self.config, self.headers, self.transaction_processor)
|
|
self.api_client = ApiClient(self.config, self.headers, self.wallet_linker)
|
|
|
|
async def _get_account_info(self):
|
|
client = TonapiClient(api_key=self.config['api_key'], is_testnet=False)
|
|
wallet, pub_key, _, _ = WalletV5R1.from_mnemonic(client=client, mnemonic=self.config['seed'])
|
|
boc = wallet.state_init.serialize().to_boc()
|
|
|
|
return {
|
|
"address": wallet.address.to_str(False, False),
|
|
"publicKey": pub_key.hex(),
|
|
"chain": "-239",
|
|
"walletStateInit": base64.b64encode(boc).decode()
|
|
}
|
|
|
|
async def topup_ton(self, username, amount):
|
|
if amount < 1 or not isinstance(amount, int):
|
|
return {"success": False, "error": "Amount must be an integer >= 1 TON"}
|
|
|
|
account = await self._get_account_info()
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
update_data = {"mode": "new", "method": "updateAdsTopupState"}
|
|
await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
|
|
headers=self.headers, data=update_data)
|
|
|
|
search_data = {"query": username, "method": "searchAdsTopupRecipient"}
|
|
search_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
|
|
headers=self.headers, data=search_data)
|
|
|
|
try:
|
|
search_result = search_resp.json()
|
|
except Exception as e:
|
|
logger.error(f"Failed to parse search response: {e}")
|
|
return {"success": False, "error": f"Invalid response from Fragment API: {str(e)}"}
|
|
|
|
recipient = search_result.get("found", {}).get("recipient")
|
|
if not recipient:
|
|
return {"success": False, "error": "User not found"}
|
|
|
|
init_data = {"recipient": recipient, "amount": amount, "method": "initAdsTopupRequest"}
|
|
init_resp = await client.post(f"https://fragment.com/api?hash={self.config['hash']}",
|
|
headers=self.headers, data=init_data)
|
|
|
|
try:
|
|
init_result = init_resp.json()
|
|
except Exception as e:
|
|
logger.error(f"Failed to parse init response: {e}")
|
|
logger.error(f"Response status: {init_resp.status_code}")
|
|
logger.error(f"Response content: {init_resp.content[:200]}")
|
|
return {"success": False, "error": f"Invalid response from Fragment API: {str(e)}"}
|
|
|
|
req_id = init_result.get("req_id")
|
|
if not req_id:
|
|
return {"success": False, "error": "Failed to initialize topup"}
|
|
|
|
tx_data = {
|
|
'account': account,
|
|
'device': {"appVersion": "5.4.3", "platform": "iphone",
|
|
"features": ["SendTransaction", {"maxMessages": 255, "name": "SendTransaction"},
|
|
{"types": ["text", "binary", "cell"], "name": "SignData"}],
|
|
"appName": "Tonkeeper", "maxProtocolVersion": 2},
|
|
'transaction': 1,
|
|
'id': req_id,
|
|
'show_sender': 1,
|
|
'method': 'getAdsTopupLink'
|
|
}
|
|
|
|
request_success, transaction_result = await self.api_client.execute_transaction_request(tx_data, account)
|
|
|
|
if not request_success:
|
|
return transaction_result
|
|
|
|
success, error, tx_hash = await self.transaction_processor.process_transaction(transaction_result)
|
|
|
|
if success:
|
|
return {
|
|
"success": True,
|
|
"data": {
|
|
"transaction_id": tx_hash,
|
|
"username": username,
|
|
"amount": amount,
|
|
"timestamp": int(time.time())
|
|
}
|
|
}
|
|
|
|
return {"success": False, "error": error}
|