Compare commits

...
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

4 Commits

@ -3,6 +3,7 @@ import config
import logging import logging
import db import db
import six import six
import re
from functools import wraps from functools import wraps
from decimal import Decimal from decimal import Decimal
@ -11,7 +12,7 @@ def log_event(f):
@wraps(f) @wraps(f)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):
msg = args[0].message msg = args[0].message
logging.info(f'"{f.__name__}" invoked from {msg.from_user["id"]} ({msg.from_user["first_name"]}) - Full command: "{msg.text}"') logging.info(f'"{f.__name__}" invoked from {msg.from_user["username"]} - Full command: "{msg.text}"')
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated_function return decorated_function
@ -52,26 +53,20 @@ def help(update, context):
@log_event @log_event
def register(update, context): def register(update, context):
uid = update.message.from_user['id'] uid = update.message.from_user['id']
un = update.message.from_user['first_name'] un = update.message.from_user['username']
uidstr = str(uid)
if db.User.filter(telegram_id=uid): if un == None:
if db.User.filter(telegram_id=uid, telegram_user=un): logging.error(f'Unable to create a new account for users without username.')
update.message.reply_text('You are already registered. Use /help to see available bot commands.') update.message.reply_text('Unable to create a new account for users without username.')
else:
update.message.reply_text('Your ID exists in the database already but your `first_name` attribute has changed. Updating.')
try:
u = db.User.get(telegram_id=uid)
u.telegram_user = un
u.save()
update.message.reply_text(f'You have been registered again as Telegram ID {uid} but with username {un}.')
except Exception as e:
logging.error(f'Unable to update user in DB: {e}. Debug: {update.message}')
update.message.reply_text('Unable to update your existing account. Ask for help.')
return False return False
if db.User.filter(telegram_id=uid):
update.message.reply_text('You are already registered.')
else: else:
try:
wallet = wownero.Wallet() wallet = wownero.Wallet()
account_index = wallet.new_account(label=un) try:
account_index = wallet.new_account(label=uidstr) # i prefer using uid because it is permanent
except Exception as e: except Exception as e:
logging.error(f'Unable to create a new account in wallet RPC: {e}. Debug: {update.message}') logging.error(f'Unable to create a new account in wallet RPC: {e}. Debug: {update.message}')
update.message.reply_text('Unable to create a new account for you. Ask for help.') update.message.reply_text('Unable to create a new account for you. Ask for help.')
@ -84,8 +79,8 @@ def register(update, context):
) )
u.save() u.save()
reply_text = [ reply_text = [
f'You have been registered as Telegram ID {uid} and username {un} and can now send and receive tips.', 'You have been registered and can now send and receive tips.',
'Ask for /help to see all available bot commands. Maybe start with /deposit to get your deposit address.' 'Ask for /help to see all available bot commands.'
] ]
update.message.reply_text(' '.join(reply_text)) update.message.reply_text(' '.join(reply_text))
except Exception as e: except Exception as e:
@ -111,11 +106,15 @@ def tip(update, context):
else: else:
target_un = context.args[0] target_un = context.args[0]
if target_un == update.message.from_user['first_name']: target_uid = context.args[0]
if target_un == update.message.from_user['username']:
#if target_uid == update.message.from_user['id']:
update.message.reply_text('You cannot tip yourself!') update.message.reply_text('You cannot tip yourself!')
return False return False
if not db.User.filter(telegram_user=target_un): if not db.User.filter(telegram_user=target_un):
#if not db.User.filter(telegram_id=target_uid):
reply_text = [ reply_text = [
'That user has not registered and cannot receive tips yet.', 'That user has not registered and cannot receive tips yet.',
'If they would like to receive a tip, have them /register with the bot.' 'If they would like to receive a tip, have them /register with the bot.'
@ -136,21 +135,19 @@ def tip(update, context):
tipper = db.User.get(telegram_id=update.message.from_user['id']) tipper = db.User.get(telegram_id=update.message.from_user['id'])
tipper_balances = wownero.Wallet().balances(account=tipper.account_index) tipper_balances = wownero.Wallet().balances(account=tipper.account_index)
if amount >= tipper_balances[1]: if amount > tipper_balances[1]:
update.message.reply_text(f'You do not have sufficient funds to send {amount} WOW. Check your /balance') update.message.reply_text(f'You do not have sufficient funds to send {amount} WOW. Check your /balance')
return False return False
# get target user details # get target user details
receiver = db.User.get(telegram_user=target_un) u = db.User.get(telegram_user=target_un)
address = wownero.Wallet().addresses(account=receiver.account_index)[0] address = wownero.Wallet().addresses(account=u.account_index)[0]
# transfer funds to user # transfer funds to user
try: try:
tx = wownero.Wallet().transfer(dest_address=address, amount=wownero.as_wownero(amount), priority=2, account=tipper.account_index) tx = wownero.Wallet().transfer(dest_address=address, amount=amount, priority=2, account=tipper.account_index)
if 'tx_hash' in tx: txhash = tx['tx_hash']
update.message.reply_text(f'Tipped @{target_un} {wownero.from_atomic(tx["amount"])} WOW! Here is the TX ID: {tx["tx_hash"]}') update.message.reply_text(f'@{update.message.from_user["username"]} has tipped @{target_un} {amount} WOW!\ntx hash: {txhash}')
else:
update.message.reply_text('Failed to send a tip. Ask for help.')
except Exception as e: except Exception as e:
logging.error(f'Unable to send transfer: {e}. Debug: {update.message}') logging.error(f'Unable to send transfer: {e}. Debug: {update.message}')
update.message.reply_text('Failed to send a tip. Ask for help.') update.message.reply_text('Failed to send a tip. Ask for help.')
@ -160,13 +157,15 @@ def tip(update, context):
@wallet_rpc_required @wallet_rpc_required
@registration_required @registration_required
@log_event @log_event
def send(update, context): def withdraw(update, context):
if len(context.args) < 2: if len(context.args) < 2:
update.message.reply_text('Not enough arguments passed.') update.message.reply_text('Not enough arguments passed.')
return False return False
# validate address # validate address
if len(context.args[0]) in [97, 107]: #print(len(context.args[0]))
if (re.match(r"Sumo[on][1-9A-HJ-NP-Za-km-z]{94}", context.args[0])) or (re.match(r"Sumi[1-9A-HJ-NP-Za-km-z]{106}", context.args[0])) or (re.match(r"Subo[1-9A-HJ-NP-Za-km-z]{94}", context.args[0])):
#if len(context.args[0]) in [97, 107]:
address = context.args[0] address = context.args[0]
else: else:
update.message.reply_text('This does not look like a valid Wownero address. Try again.') update.message.reply_text('This does not look like a valid Wownero address. Try again.')
@ -191,22 +190,53 @@ def send(update, context):
# transfer funds to given address # transfer funds to given address
try: try:
tx = wownero.Wallet().transfer(dest_address=address, amount=wownero.as_wownero(amount), priority=2, account=sender.account_index) tx = wownero.Wallet().transfer(dest_address=address, amount=amount, priority=2, account=sender.account_index)
if 'tx_hash' in tx: update.message.reply_text(f'Sent {amount} WOW! Tx: {tx}')
update.message.reply_text(f'Sent {wownero.from_atomic(tx["amount"])} WOW! Here is the TX ID: {tx["tx_hash"]}')
else:
update.message.reply_text('Failed to send Wownero. Ask for help.')
except Exception as e: except Exception as e:
logging.error(f'Unable to send transfer: {e}. Debug: {update.message}') logging.error(f'Unable to send transfer: {e}. Debug: {update.message}')
update.message.reply_text('Failed to send Wownero. Ask for help.') update.message.reply_text('Failed to send Wownero. Ask for help.')
@wallet_rpc_required
@registration_required
@log_event
def sweepall(update, context):
if len(context.args) < 1:
update.message.reply_text('Not enough arguments passed.')
return False
if (re.match(r"Sumo[on][1-9A-HJ-NP-Za-km-z]{94}", context.args[0])) or (re.match(r"Sumi[1-9A-HJ-NP-Za-km-z]{106}", context.args[0])) or (re.match(r"Subo[1-9A-HJ-NP-Za-km-z]{94}", context.args[0])):
address = context.args[0]
else:
update.message.reply_text('This does not look like a valid Wownero address. Try again.')
return False
sender = db.User.get(telegram_id=update.message.from_user['id'])
# validate amount
sender_balances = wownero.Wallet().balances(account=sender.account_index)
print(sender_balances)
if sender_balances[1] < 1 :
update.message.reply_text(f'You do not have sufficient funds to empty your wallet. Check your /balance')
return False
# transfer funds to given address
try:
tx = wownero.Wallet().sweepall(dest_address=address, priority=2, account=sender.account_index)
update.message.reply_text(f'Sent all unlocked WOW! Tx: {tx}')
except Exception as e:
logging.error(f'Unable to send sweepall: {e}. Debug: {update.message}')
update.message.reply_text('Failed to send Wownero. Ask for help.')
@wallet_rpc_required @wallet_rpc_required
@registration_required @registration_required
@log_event @log_event
def balance(update, context): def balance(update, context):
u = db.User.get(telegram_id=update.message.from_user['id']) u = db.User.get(telegram_id=update.message.from_user['id'])
balances = wownero.Wallet().balances(account=u.account_index) balances = wownero.Wallet().balances(account=u.account_index)
update.message.reply_text(f'Available balance for {u.telegram_user}: {float(balances[1])} WOW ({float(balances[0])} WOW locked)') update.message.reply_text(f'Available balance for {update.message.from_user["username"]}: {float(balances[1])} WOW ({float(balances[0])} WOW locked)')
@wallet_rpc_required @wallet_rpc_required
@registration_required @registration_required
@ -214,13 +244,26 @@ def balance(update, context):
def deposit(update, context): def deposit(update, context):
u = db.User.get(telegram_id=update.message.from_user['id']) u = db.User.get(telegram_id=update.message.from_user['id'])
address = wownero.Wallet().addresses(account=u.account_index)[0] address = wownero.Wallet().addresses(account=u.account_index)[0]
update.message.reply_text(f'Deposit address for {u.telegram_user}: {address}') update.message.reply_text(f'Deposit address for {update.message.from_user["username"]}: {address}')
@wallet_rpc_required @wallet_rpc_required
@log_event @log_event
def debug(update, context): def debug(update, context):
if is_tg_admin(update.message.from_user['id']): if is_tg_admin(update.message.from_user['id']):
pass # tx = wownero.Wallet().transfer(
# dest_address='WW2vmEGV68ZFeQWwPEJda3UcdWCPfWBnDK1Y6MB9Uojx9adBhCxfx9F51TomRjmD3z7Gyogie3mfVQEkRQjLxqbs1KMzaozDw',
# amount=Decimal(2),
# priority=2,
# account=0
# )
# update.message.reply_text(str(tx))
# balances = wownero.Wallet().balances(account=0)
# addresses = wownero.Wallet().addresses(account=0)
# accounts = wownero.Wallet().accounts()
# a = []
# for i in accounts:
# a.append(str(wownero.Wallet().balances(account=i)[1]))
update.message.reply_text('sup boss')
else: else:
update.message.reply_text('you cant do that.') update.message.reply_text('you cant do that.')
@ -236,10 +279,10 @@ all_commands = {
'example': '/tip <username> <amount> <message>', 'example': '/tip <username> <amount> <message>',
'help': 'Tip a user in Wownero' 'help': 'Tip a user in Wownero'
}, },
'send': { 'withdraw': {
'func': send, 'func': withdraw,
'example': '/send <address> <amount>', 'example': '/withdraw <address> <amount>',
'help': 'Send Wownero to a specified Wownero address' 'help': 'Withdraw to a specified Wownero address'
}, },
'balance': { 'balance': {
'func': balance, 'func': balance,
@ -256,11 +299,21 @@ all_commands = {
'example': '/deposit', 'example': '/deposit',
'help': 'Show your Wownero wallet address for transferring funds to' 'help': 'Show your Wownero wallet address for transferring funds to'
}, },
'empty': {
'func': sweepall,
'example': '/empty <address>',
'help': 'Withdraw all your coins to a specified Wownero address'
},
'help': { 'help': {
'func': help, 'func': help,
'example': '/help', 'example': '/help',
'help': 'Show available commands for the bot', 'help': 'Show available commands for the bot',
}, },
'start': {
'func': help,
'example': '/start',
'help': 'Show available commands for the bot',
},
'debug': { 'debug': {
'func': debug, 'func': debug,
'admin': True 'admin': True

@ -5,7 +5,6 @@ import operator
import config import config
from decimal import Decimal from decimal import Decimal
PICOWOW = Decimal('0.00000000001') PICOWOW = Decimal('0.00000000001')
class Wallet(object): class Wallet(object):
@ -102,12 +101,25 @@ class Wallet(object):
transfer = self.make_wallet_rpc('transfer', data) transfer = self.make_wallet_rpc('transfer', data)
return transfer return transfer
def sweepall(self, dest_address, priority, account):
data = {
'account_index': account,
'address': dest_address,
'priority': priority,
'unlock_time': 0,
'get_tx_key': True,
'get_tx_hex': True,
'new_algorithm': True,
'do_not_relay': False,
}
sweepall = self.make_wallet_rpc('sweep_all', data)
return sweepall
def to_atomic(amount): def to_atomic(amount):
if not isinstance(amount, (Decimal, float) + six.integer_types): if not isinstance(amount, (Decimal, float) + six.integer_types):
raise ValueError("Amount '{}' doesn't have numeric type. Only Decimal, int, long and " raise ValueError("Amount '{}' doesn't have numeric type. Only Decimal, int, long and "
"float (not recommended) are accepted as amounts.") "float (not recommended) are accepted as amounts.")
return int(amount * 10**11) return int(amount / PICOWOW)
def from_atomic(amount): def from_atomic(amount):
return (Decimal(amount) * PICOWOW).quantize(PICOWOW) return (Decimal(amount) * PICOWOW).quantize(PICOWOW)