async def make_transaction_to_address(source_user, amount, withdraw_address, uid, target_id=None, giveaway_id=0, verify_address=False): # Do not validate address for giveaway tx because we do not know it yet if verify_address: # Check to see if the withdraw address is valid #pulowi falta servicio de validacion #wallet_command = {'action': 'validate_account_number', # 'account': withdraw_address} #address_validation = await communicate_wallet_async(wallet_command) #if ((withdraw_address[:4] == 'ban_' and len(withdraw_address) != 64) # or address_validation['valid'] != '1'): # raise util.TipBotException('invalid_address') if ((withdraw_address[:4] == 'tgm_' and len(withdraw_address) != 106)): raise util.TipBotException('invalid_address') amount = int(amount) if amount >= 1: # See if destination address belongs to a user if target_id is None: user = db.get_user_by_wallet_address(withdraw_address) if user is not None: target_id=user.user_id # Update pending send for user db.create_transaction(source_user, uid, withdraw_address,amount, target_id, giveaway_id) logger.info('TX queued, uid %s', uid) else: raise util.TipBotException('balance_error') return amount
def find_address(input_text): address = input_text.split(' ') if len(address) == 1: raise util.TipBotException("address_not_found") elif address[1] is None: raise util.TipBotException("address_not_found") return address[1]
async def givearai(message): if message.channel.is_private: return try: # One giveaway at a time if db.is_active_giveaway(): await post_dm(message.author, GIVEAWAY_EXISTS) return split_content = message.content.split(' ') if len(split_content) > 2: amount = find_amount(split_content[1]) fee = find_amount(split_content[2]) else: raise util.TipBotException("usage_error") if amount < GIVEAWAY_MINIMUM: raise util.TipBotException("usage_error") max_fee = int(0.05 * amount) if fee > max_fee: await post_response(message, GIVEAWAY_MAX_FEE) return if 0 > fee: raise util.TipBotException("usage_error") user = db.get_user_by_id(message.author.id) if user is None: return balance = await wallet.get_balance(user) user_balance = balance['available'] if user_balance < amount: await add_x_reaction(message) await post_dm(message.author, INSUFFICIENT_FUNDS_TEXT) return end_time = datetime.datetime.now() + datetime.timedelta( minutes=GIVEAWAY_DURATION) nano_amt = amount / 1000000 giveaway = db.start_giveaway(message.author.id, message.author.name, nano_amt, end_time, message.channel.id, entry_fee=fee) uid = str(uuid.uuid4()) await wallet.make_transaction_to_address(user, amount, None, uid, giveaway_id=giveaway.id) if fee > 0: await post_response(message, GIVEAWAY_STARTED_FEE, message.author.name, nano_amt, fee, fee) else: await post_response(message, GIVEAWAY_STARTED, message.author.name, nano_amt) asyncio.get_event_loop().create_task(start_giveaway_timer()) db.update_tip_stats(user, amount) db.add_contestant(message.author.id, override_ban=True) except util.TipBotException as e: if e.error_type == "amount_not_found" or e.error_type == "usage_error": await post_dm(message.author, GIVEAWAY_USAGE)
async def tipsplit(message): if message.channel.is_private: return try: amount = find_amount(message.content) # Make sure amount is valid and at least 1 user is mentioned if amount < 1 or len(message.mentions) < 1: raise util.TipBotException("usage_error") if int(amount / len(message.mentions)) < 1: raise util.TipBotException("invalid_tipsplit") # Create tip list users_to_tip = [] for member in message.mentions: # Disregard mentions of self and exempt users if member.id not in settings.exempt_users and member.id != message.author.id and not db.is_banned( member.id) and not member.bot: users_to_tip.append(member) if len(users_to_tip) < 1: raise util.TipBotException("no_valid_recipient") # Remove duplicates users_to_tip = list(set(users_to_tip)) # Make sure user has enough in their balance user = db.get_user_by_id(message.author.id) if user is None: return balance = await wallet.get_balance(user) user_balance = balance['available'] if user_balance < amount: await add_x_reaction(ctx.message) await post_dm(message.author, INSUFFICIENT_FUNDS_TEXT) return # Distribute tips tip_amount = int(amount / len(users_to_tip)) # Recalculate amount as it may be different since truncating decimal real_amount = tip_amount * len(users_to_tip) for member in users_to_tip: uid = str(uuid.uuid4()) actual_amt = await wallet.make_transaction_to_user( user, tip_amount, member.id, member.name, uid) # Tip didn't go through if actual_amt == 0: amount -= tip_amount else: await post_dm(member, TIP_RECEIVED_TEXT, tip_amount, message.author.name) await react_to_message(message, amount) db.update_tip_stats(user, real_amount) except util.TipBotException as e: if e.error_type == "amount_not_found" or e.error_type == "usage_error": await post_dm(message.author, TIPSPLIT_USAGE) elif e.error_type == "invalid_tipsplit": await post_dm(message.author, TIPSPLIT_SMALL) elif e.error_type == "no_valid_recipient": await post_dm(message.author, TIP_SELF) else: await post_response(message, TIP_ERROR_TEXT)
def make_transaction_to_user(user_id, amount, target_user_id, target_user_name): if check_balance(user_id, amount): target_user = create_or_fetch_user(target_user_id, target_user_name) user = db.get_user_by_id(user_id) if db.move_funds(user, amount, target_user): logger.info('tip successful. (from: %s, to: %s, amount: %.3f)', user_id, target_user.user_id, amount) return else: raise util.TipBotException("error") else: raise util.TipBotException("insufficient_funds")
async def tip(message): if message.channel.is_private: return try: amount = find_amount(message.content) # Make sure amount is valid and at least 1 user is mentioned if amount < 1 or len(message.mentions) < 1: raise util.TipBotException("usage_error") # Create tip list users_to_tip = [] for member in message.mentions: # Disregard mentions of exempt users and self if member.id not in settings.exempt_users and member.id != message.author.id and not db.is_banned( member.id) and not member.bot: users_to_tip.append(member) if len(users_to_tip) < 1: raise util.TipBotException("no_valid_recipient") # Cut out duplicate mentions users_to_tip = list(set(users_to_tip)) # Make sure this user has enough in their balance to complete this tip required_amt = amount * len(users_to_tip) user = db.get_user_by_id(message.author.id) balance = await wallet.get_balance(user) user_balance = balance['available'] if user_balance < required_amt: await add_x_reaction(message) await post_dm(message.author, INSUFFICIENT_FUNDS_TEXT) return # Distribute tips for member in users_to_tip: uid = str(uuid.uuid4()) actual_amt = await wallet.make_transaction_to_user( user, amount, member.id, member.name, uid) # Something went wrong, tip didn't go through if actual_amt == 0: required_amt -= amount else: await post_dm(member, TIP_RECEIVED_TEXT, actual_amt, message.author.name) # Post message reactions await react_to_message(message, required_amt) # Update tip stats db.update_tip_stats(user, required_amt) except util.TipBotException as e: if e.error_type == "amount_not_found" or e.error_type == "usage_error": await post_dm(message.author, TIP_USAGE) elif e.error_type == "no_valid_recipient": await post_dm(message.author, TIP_SELF) else: await post_response(message, TIP_ERROR_TEXT)
def find_amount(input_text): regex = r'(?:^|\s)(\d*\.?\d+)(?=$|\s)' matches = re.findall(regex, input_text, re.IGNORECASE) if len(matches) == 1: try: assert Decimal(matches[0]).as_tuple().exponent >= -6 return float(matches[0].strip()) except AssertionError: raise util.TipBotException("too_many_decimals") else: raise util.TipBotException("amount_not_found")
def find_user_id(input_text): regex = r'(?:^|\s)<@!?(\w*)>(?=$|\s)' matches = re.findall(regex, input_text, re.IGNORECASE) if len(matches) == 1: return matches[0].strip() else: raise util.TipBotException("user_not_found")
def find_amount(input_text): regex = r'(?:^|\s)(\d*\.?\d+)(?=$|\s)' matches = re.findall(regex, input_text, re.IGNORECASE) if len(matches) == 1: return float(matches[0].strip()) else: raise util.TipBotException("amount_not_found")
def find_address(input_text): regex = r'\w{25,34}' matches = re.findall(regex, input_text, re.IGNORECASE) if len(matches) == 1: return matches[0].strip() else: raise util.TipBotException("address_not_found")
def find_address(input_text: str) -> str: # regex catching all kinds of Peercoin addreses regex = r'(?:(?:tpc|pc)(?:0(?:[ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59})|1[ac-hj-np-z02-9]{8,87})|(?:[Pp]|[mn2])[a-km-zA-HJ-NP-Z1-9]{25,39})' matches = re.findall(regex, input_text, re.IGNORECASE) if len(matches) == 1: return matches[0].strip() else: raise util.TipBotException("address_not_found")
async def make_transaction_to_address(source_user, amount, withdraw_address, uid, target_id=None, giveaway_id=0, verify_address=False): # Do not validate address for giveaway tx because we do not know it yet if verify_address: # Check to see if the withdraw address is valid wallet_command = { 'action': 'validate_account_number', 'account': withdraw_address } address_validation = await asyncio.get_event_loop().run_in_executor( None, communicate_wallet, wallet_command) # If the address was the incorrect length, did not start with xrb_ or nano_ or was deemed invalid by the node, return an error. address_prefix_valid = withdraw_address[:4] == 'ban_' \ or withdraw_address[:5] == 'ban_' if len(withdraw_address) != 64 or not address_prefix_valid \ or address_validation['valid'] != '1': raise util.TipBotException('invalid_address') amount = int(amount) if amount >= 1: # See if destination address belongs to a user if target_id is None: user = db.get_user_by_wallet_address(withdraw_address) if user is not None: target_id = user.user_id # Update pending send for user db.create_transaction(source_user, uid, withdraw_address, amount, target_id, giveaway_id) logger.info('TX queued, uid %s', uid) else: raise util.TipBotException('balance_error') return amount
def make_transaction_to_address(user, amount, address): rpc_connection = connect() txid = rpc_connection.sendtoaddress(address, round(amount, 6), "tippbot withdraw") logger.info( 'creating withdraw transaction (user: %s, amount: %.3f, address: %s, txid: %s)', user.user_id, amount, address, txid) if db.create_withdraw_transaction(txid, amount, user): logger.info('withdraw successful.') return txid else: raise util.TipBotException("error")
def make_transaction_to_address(user, amount, address): txfee = 0.01 commands = [["settxfee", txfee]] rpc_connection = connect() result = rpc_connection.batch_(commands) if result[0]: commands = [[ "sendtoaddress", address, amount - txfee, "ztipbot withdraw" ]] result = rpc_connection.batch_(commands) txid = result[0] logger.info( 'creating withdraw transaction (user: %s, amount: %.3f, address: %s)', user.user_id, amount, address) if db.create_withdraw_transaction(txid, amount, user): logger.info('withdraw successful.') return else: raise util.TipBotException("error")
async def rain(message): if message.channel.is_private: return try: amount = find_amount(message.content) if amount < RAIN_MINIMUM: raise util.TipBotException("usage_error") # Create tip list users_to_tip = [] active_user_ids = db.get_active_users(RAIN_DELTA) if len(active_user_ids) < 1: raise util.TipBotException("no_valid_recipient") for auid in active_user_ids: dmember = message.server.get_member(auid) if dmember is not None and (dmember.status == discord.Status.online or dmember.status == discord.Status.idle): if dmember.id not in settings.exempt_users and dmember.id != message.author.id and not db.is_banned( dmember.id) and not dmember.bot: users_to_tip.append(dmember) users_to_tip = list(set(users_to_tip)) if len(users_to_tip) < 1: raise util.TipBotException("no_valid_recipient") if int(amount / len(users_to_tip)) < 1: raise util.TipBotException("invalid_tipsplit") user = db.get_user_by_id(message.author.id) if user is None: return balance = await wallet.get_balance(user) user_balance = balance['available'] if user_balance < amount: await add_x_reaction(message) await post_dm(message.author, INSUFFICIENT_FUNDS_TEXT) return # Distribute Tips tip_amount = int(amount / len(users_to_tip)) # Recalculate actual tip amount as it may be smaller now real_amount = tip_amount * len(users_to_tip) for member in users_to_tip: uid = str(uuid.uuid4()) actual_amt = await wallet.make_transaction_to_user( user, tip_amount, member.id, member.name, uid) # Tip didn't go through for some reason if actual_amt == 0: amount -= tip_amount else: await post_dm(member, TIP_RECEIVED_TEXT, actual_amt, message.author.name) # Message React await react_to_message(message, amount) await client.add_reaction(message, '\U0001F4A6') # Sweat Drops db.update_tip_stats(user, real_amount) except util.TipBotException as e: if e.error_type == "amount_not_found" or e.error_type == "usage_error": await post_dm(message.author, RAIN_USAGE) elif e.error_type == "no_valid_recipient": await post_dm(message.author, RAIN_NOBODY) elif e.error_type == "invalid_tipsplit": await post_dm(message.author, TIPSPLIT_SMALL) else: await post_response(message, TIP_ERROR_TEXT)