Spaces:
Paused
Paused
""" | |
Extol Wallet & Payment Integration for DragMusic Bot | |
Commands: | |
/addapi <api_key> (private chat only) | |
/addextol <address> | |
/removeextol | |
/payextol <amount> | |
/checkextol | |
/extolbal | |
/sendextol <to_address> <amount> | |
""" | |
import os | |
import httpx | |
from pyrogram import filters | |
from DragMusic import app | |
from DragMusic.utils.database import mongodb | |
from pyrogram.types import Message | |
from datetime import datetime | |
from pyrogram.enums import ParseMode | |
API_BASE_URL = "https://marketapi.animerealms.org" | |
api_keys_collection = mongodb.iac_api_keys | |
addresses_collection = mongodb.iac_extol_addresses | |
payments_collection = mongodb.iac_payments | |
# Async helpers for MongoDB | |
async def set_user_api_key(user_id: int, api_key: str): | |
await api_keys_collection.update_one( | |
{"user_id": user_id}, | |
{"$set": {"api_key": api_key}}, | |
upsert=True | |
) | |
async def get_user_api_key(user_id: int): | |
doc = await api_keys_collection.find_one({"user_id": user_id}) | |
return doc["api_key"] if doc and "api_key" in doc else None | |
async def set_user_address(user_id: int, address: str): | |
await addresses_collection.update_one( | |
{"user_id": user_id}, | |
{"$set": {"address": address}}, | |
upsert=True | |
) | |
async def get_user_address(user_id: int): | |
doc = await addresses_collection.find_one({"user_id": user_id}) | |
return doc["address"] if doc and "address" in doc else None | |
async def remove_user_address(user_id: int): | |
await addresses_collection.delete_one({"user_id": user_id}) | |
async def set_last_payment_id(user_id: int, payment_id: str): | |
await payments_collection.update_one( | |
{"user_id": user_id}, | |
{"$set": {"last_payment_id": payment_id}}, | |
upsert=True | |
) | |
async def get_last_payment_id(user_id: int): | |
doc = await payments_collection.find_one({"user_id": user_id}) | |
return doc["last_payment_id"] if doc and "last_payment_id" in doc else None | |
async def save_payment(user_id: int, payment_id: str, address: str, amount: float, payment_url: str): | |
await payments_collection.insert_one({ | |
"user_id": user_id, | |
"payment_id": payment_id, | |
"address": address, | |
"amount": amount, | |
"payment_url": payment_url, | |
"created_at": datetime.utcnow() | |
}) | |
async def get_user_payments(user_id: int, limit: int = 10): | |
cursor = payments_collection.find({"user_id": user_id}).sort("created_at", -1).limit(limit) | |
return await cursor.to_list(length=limit) | |
# /addapi <api_key> (private chat only) | |
async def set_api_key_handler(client, message: Message): | |
args = message.text.split() | |
if len(args) != 2: | |
await message.reply_text("Usage: /addapi <your_api_key>") | |
return | |
await set_user_api_key(message.from_user.id, args[1]) | |
await message.reply_text("β Extol API Key set successfully.") | |
# Helper to check API key | |
async def check_api_key(message: Message): | |
user_id = message.from_user.id | |
api_key = await get_user_api_key(user_id) | |
if not api_key: | |
await message.reply_text("[IAC Marketplace] API key not set. Use /addapi <your_api_key> in bot DM to set it.") | |
return None | |
return api_key | |
# /addextol <address> | |
async def add_extol_handler(client, message: Message): | |
args = message.text.split() | |
if len(args) != 2 or not args[1].startswith("EXT"): | |
await message.reply_text("β Provide a valid Extol address starting with EXT.\n Usage: /addextol <address>") | |
return | |
await set_user_address(message.from_user.id, args[1]) | |
await message.reply_text(f"β Extol address saved: `{args[1]}`.") | |
# /removeextol | |
async def remove_extol_handler(client, message: Message): | |
await remove_user_address(message.from_user.id) | |
await message.reply_text("β Extol address removed.") | |
# /payextol <amount> | |
async def pay_extol_handler(client, message: Message): | |
args = message.text.split() | |
if len(args) != 2 or not args[1].isdigit(): | |
await message.reply_text("β Enter a valid numeric amount.\n Usage: /payextol <amount>") | |
return | |
address = await get_user_address(message.from_user.id) | |
if not address: | |
await message.reply_text("β Use /addextol <address> to set your address first.") | |
return | |
msg = await message.reply_text("π Generating payment link...") | |
data = {"address": address, "amount": int(args[1])} | |
resp = await extol_request(message.from_user.id, "/api/create-payment", method="POST", data=data) | |
if not resp.get("ok"): | |
return await msg.edit(f"β Error: `{resp.get('error')}`") | |
payment_id = resp["payment_id"] | |
await set_last_payment_id(message.from_user.id, payment_id) | |
# Save payment to history for /checkextol | |
await save_payment(message.from_user.id, payment_id, address, int(args[1]), resp["payment_url"]) | |
await msg.edit(f"β <a href='{resp['payment_url']}'>Click here to pay</a>", disable_web_page_preview=True, parse_mode=ParseMode.HTML) | |
# /checkextol | |
async def check_extol_handler(client, message: Message): | |
payments = await get_user_payments(message.from_user.id, limit=10) | |
if not payments: | |
await message.reply_text("β No recent payments found.") | |
return | |
msg = await message.reply_text("π Checking last 10 payment statuses...") | |
status_lines = [] | |
for p in payments: | |
payment_id = p["payment_id"] | |
amount = p["amount"] | |
pay_url = p["payment_url"] | |
resp = await extol_request(message.from_user.id, "/api/payment-status", params={"payment_id": payment_id}) | |
if not resp.get("ok"): | |
status_str = f"β Error: {resp.get('error') or 'Unknown'}" | |
else: | |
status = resp["status"] | |
if status == "paid": | |
status_str = f"β <b>Paid</b><br>From: <code>{resp.get('from_address', '-')}</code>, At: <code>{resp.get('paid_at', '-')}</code>" | |
elif status == "timeout": | |
status_str = f"β <b>Timeout</b><br>Expired: <code>{resp.get('expired_at', '-')}</code>" | |
else: | |
status_str = "β³ <b>Pending</b>" | |
status_lines.append(f"Amount: <code>{amount}</code><br>" | |
f'<a href="{pay_url}">Click here to pay</a><br>' | |
f"ID: <code>{payment_id}</code><br>{status_str}") | |
await msg.edit("\n\n".join(status_lines), disable_web_page_preview=True, parse_mode=ParseMode.HTML) | |
# /extolbal | |
async def extol_balance_handler(client, message: Message): | |
msg = await message.reply_text("π Fetching Extol balance...") | |
resp = await extol_request(message.from_user.id, "/api/balance") | |
if not resp.get("ok"): | |
return await msg.edit(f"β Error: `{resp.get('error')}`") | |
balance = resp.get("balance", 0) | |
address = resp.get("address", "Unknown") | |
await msg.edit(f"π° Balance: {balance} EXT\nπ·οΈ Address: {address}") | |
# /sendextol <to_address> <amount> | |
async def send_extol_handler(client, message: Message): | |
args = message.text.split() | |
if len(args) != 3 or not args[2].isdigit() or not args[1].startswith("EXT"): | |
await message.reply_text("Usage: /sendextol <to_address> <amount>") | |
return | |
to_address, amt = args[1], int(args[2]) | |
if amt <= 0: | |
await message.reply_text("β Amount must be positive.") | |
return | |
msg = await message.reply_text("π Sending Extol...") | |
resp = await extol_request( | |
message.from_user.id, | |
"/api/withdraw", | |
method="GET", | |
params={"amount": amt, "address": to_address}, | |
) | |
if not resp.get("ok"): | |
error_msg = resp.get('error') or 'Unknown error (no message from API)' | |
code = resp.get('code') | |
if code is not None: | |
error_msg = f"(code {code}) {error_msg}" | |
return await msg.edit(f"β Error: {error_msg}") | |
link = resp.get("link", "No explorer link.") | |
await msg.edit(f"β Sent {amt} EXT to {to_address} \n<a href='{link}'>View Transaction</a>", disable_web_page_preview=True, parse_mode=ParseMode.HTML) | |
# --- HTTPX helper --- | |
async def extol_request(user_id, path, method="GET", data=None, params=None): | |
api_key = await get_user_api_key(user_id) | |
if not api_key: | |
return {"ok": False, "error": "API key not set. Use /addapi <key> in DM."} | |
async with httpx.AsyncClient() as client: | |
headers = {"api-key": api_key} | |
try: | |
if method == "GET": | |
r = await client.get(f"{API_BASE_URL}{path}", headers=headers, params=params, timeout=10) | |
else: | |
r = await client.post(f"{API_BASE_URL}{path}", headers=headers, json=data, timeout=10) | |
return r.json() | |
except Exception as e: | |
return {"ok": False, "error": str(e)} |