|
""" |
|
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 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) |
|
|
|
|
|
@app.on_message(filters.command("addapi") & filters.private) |
|
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.") |
|
|
|
|
|
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 |
|
|
|
|
|
@app.on_message(filters.command("addextol")) |
|
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]}`.") |
|
|
|
|
|
@app.on_message(filters.command("removeextol")) |
|
async def remove_extol_handler(client, message: Message): |
|
await remove_user_address(message.from_user.id) |
|
await message.reply_text("β
Extol address removed.") |
|
|
|
|
|
@app.on_message(filters.command("payextol")) |
|
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) |
|
|
|
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) |
|
|
|
|
|
@app.on_message(filters.command("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) |
|
|
|
|
|
@app.on_message(filters.command("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}") |
|
|
|
|
|
@app.on_message(filters.command("sendextol")) |
|
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) |
|
|
|
|
|
|
|
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)} |