def handle_send(message): """ Extracts send command information from a PM command :param message: :return: """ parsed_text = parse_text(str(message.body)) username = str(message.author) message_time = datetime.utcfromtimestamp( message.created_utc) # time the reddit message was created entry_id = add_history_record( username=username, action="send", comment_or_message="message", comment_id=message.name, reddit_time=message_time.strftime("%Y-%m-%d %H:%M:%S"), comment_text=str(message.body)[:255], ) response = {"username": username} # check that there are enough fields (i.e. a username) if len(parsed_text) <= 2: update_history_notes(entry_id, "no recipient or amount specified") response["status"] = 110 return response # check that it wasn't a mistyped currency code or something if parsed_text[2] in EXCLUDED_REDDITORS: response["status"] = 140 return response # pull sender account info sender_info = tipper_functions.account_info(response["username"]) if not sender_info: update_history_notes(entry_id, "user does not exist") response["status"] = 100 return response # parse the amount try: response["amount"] = parse_raw_amount(parsed_text, response["username"]) except TipError as err: response["status"] = 120 response["amount"] = parsed_text[1] update_history_notes(entry_id, err.sql_text) return response # check if it's above the program minimum if response["amount"] < nano_to_raw(PROGRAM_MINIMUM): update_history_notes(entry_id, "amount below program limit") response["status"] = 130 return response # check the user's balance if response["amount"] > sender_info["balance"]: update_history_notes(entry_id, "insufficient funds") response["status"] = 160 return response recipient_text = parsed_text[2] # catch invalid redditor AND address try: recipient_info = parse_recipient_username(recipient_text) except TipError as err: update_history_notes(entry_id, err.sql_text) response["recipient"] = recipient_text response["status"] = 170 return response # if we have a username, pull their info if "username" in recipient_info.keys(): response["recipient"] = recipient_info["username"] recipient_name = recipient_info["username"] recipient_info = tipper_functions.account_info(recipient_name) response["status"] = 10 if recipient_info is None: recipient_info = tipper_functions.add_new_account( response["recipient"]) response["status"] = 20 elif not recipient_info["opt_in"]: response["status"] = 190 return response # check if it's an address else: # otherwise, just use the address. Everything is None except address recipient_info["minimum"] = 0 response["recipient"] = recipient_info["address"] response["status"] = 30 # check the send amount is above the user minimum, if a username is provided # if it was just an address, this would be -1 if response["amount"] < recipient_info["minimum"]: update_history_notes(entry_id, "below user minimum") response["status"] = 180 response["minimum"] = recipient_info["minimum"] return response response["hash"] = send( sender_info["address"], sender_info["private_key"], response["amount"], recipient_info["address"], )["hash"] # if it was an address, just send to the address if "username" not in recipient_info.keys(): sql = ( "UPDATE history SET notes = %s, address = %s, username = %s, recipient_username = %s, " "recipient_address = %s, amount = %s, return_status = %s WHERE id = %s" ) val = ( "send to address", sender_info["address"], sender_info["username"], None, recipient_info["address"], str(response["amount"]), "cleared", entry_id, ) tipper_functions.exec_sql(sql, val) LOGGER.info( f"Sending Nano: {sender_info['address']} {sender_info['private_key']} {response['amount']} {recipient_info['address']}" ) return response # Update the sql and send the PMs sql = ( "UPDATE history SET notes = %s, address = %s, username = %s, recipient_username = %s, " "recipient_address = %s, amount = %s, hash = %s, return_status = %s WHERE id = %s" ) val = ( "sent to user", sender_info["address"], sender_info["username"], recipient_info["username"], recipient_info["address"], str(response["amount"]), response["hash"], "cleared", entry_id, ) tipper_functions.exec_sql(sql, val) LOGGER.info( f"Sending Nano: {sender_info['address']} {sender_info['private_key']} {response['amount']} {recipient_info['address']} {recipient_info['username']}" ) if response["status"] == 20: subject = "Congrats on receiving your first Nano Tip!" message_text = (WELCOME_TIP % ( response["amount"] / 10**30, recipient_info["address"], recipient_info["address"], ) + COMMENT_FOOTER) send_pm(recipient_info["username"], subject, message_text) return response else: if not recipient_info["silence"]: receiving_new_balance = check_balance(recipient_info["address"]) subject = "You just received a new Nano tip!" message_text = (NEW_TIP % ( response["amount"] / 10**30, recipient_info["address"], receiving_new_balance[0] / 10**30, receiving_new_balance[1] / 10**30, response["hash"], ) + COMMENT_FOOTER) send_pm(recipient_info["username"], subject, message_text) return response
def send_from_comment(message): """ Error codes: Success 10 - sent to existing user 20 - sent to new user 30 - sent to address 40 - donated to nanocenter project Tip not sent 100 - sender account does not exist 110 - Amount and/or recipient not specified 120 - could not parse send amount 130 - below program minimum 140 - currency code issue 150 - below 1 nano for untracked sub 160 - insufficient funds 170 - invalid address / recipient 180 - below recipient minimum 200 - No Nanocenter Project specified 210 - Nanocenter Project does not exist Extracts send command information from a PM command :param message: :return: response string """ parsed_text = parse_text(str(message.body)) response = {"username": str(message.author)} message_time = datetime.datetime.utcfromtimestamp( message.created_utc) # time the reddit message was created entry_id = add_history_record( username=response["username"], action="send", comment_or_message="comment", comment_id=message.name, reddit_time=message_time.strftime("%Y-%m-%d %H:%M:%S"), comment_text=str(message.body)[:255], ) # check if it's a donate command at the end if parsed_text[-3] in DONATE_COMMANDS: parsed_text = parsed_text[-3:] # don't do anything if the first word is a tip command or username elif (parsed_text[0] in [ f"/u/{TIP_BOT_USERNAME}", f"u/{TIP_BOT_USERNAME}" ]) or (parsed_text[0] in TIP_COMMANDS): pass # if the second to last is a username or tip command, redifine parsed text elif (parsed_text[-2] in [ f"/u/{TIP_BOT_USERNAME}", f"u/{TIP_BOT_USERNAME}" ]) or (parsed_text[-2] in TIP_COMMANDS): parsed_text = parsed_text[-2:] # before we can do anything, check the subreddit status for generating the response # check if amount is above subreddit minimum. response["subreddit"] = str(message.subreddit).lower() sql = "SELECT status FROM subreddits WHERE subreddit=%s" val = (response["subreddit"], ) results = tipper_functions.query_sql(sql, val) if len(results) == 0: response["subreddit_minimum"] = 1 results = [["untracked"]] elif results[0][0] in ["full", "friendly", "minimal", "silent"]: response["subreddit_minimum"] = 0 else: response["subreddit_minimum"] = 1 response["subreddit_status"] = results[0][0] # check that it wasn't a mistyped currency code or something if parsed_text[2] in EXCLUDED_REDDITORS: response["status"] = 140 return response if parsed_text[0] in TIP_COMMANDS and len(parsed_text) <= 1: update_history_notes(entry_id, "no recipient or amount specified") response["status"] = 110 return response if parsed_text[0] in DONATE_COMMANDS and len(parsed_text) <= 2: response["status"] = 110 update_history_notes(entry_id, "no recipient or amount specified") return response # pull sender account info sender_info = tipper_functions.account_info(response["username"]) if not sender_info: update_history_notes(entry_id, "user does not exist") response["status"] = 100 return response # parse the amount try: response["amount"] = parse_raw_amount(parsed_text, response["username"]) except TipError as err: response["status"] = 120 response["amount"] = parsed_text[1] update_history_notes(entry_id, err.sql_text) return response # check if it's above the program minimum if response["amount"] < nano_to_raw(PROGRAM_MINIMUM): update_history_notes(entry_id, "amount below program limit") response["status"] = 130 return response # check the user's balance if response["amount"] > sender_info["balance"]: update_history_notes(entry_id, "insufficient funds") response["status"] = 160 return response if response["amount"] < nano_to_raw(response["subreddit_minimum"]): update_history_notes(entry_id, "amount below subreddit minimum") response["status"] = 150 return response # if it's a normal send, pull the account author # we will distinguish users from donations by the presence of a private key if parsed_text[0] in (TIP_COMMANDS + [f"/u/{TIP_BOT_USERNAME}", f"u/{TIP_BOT_USERNAME}"]): response["status"] = 10 response["recipient"] = str(message.parent().author) recipient_info = tipper_functions.account_info(response["recipient"]) if not recipient_info: response["status"] = 20 recipient_info = tipper_functions.add_new_account( response["recipient"]) elif recipient_info["silence"]: response["status"] = 11 elif not recipient_info["opt_in"]: response["status"] = 190 return response elif parsed_text[0] in DONATE_COMMANDS: response["recipient"] = parsed_text[2] results = tipper_functions.query_sql( "FROM projects SELECT address WHERE project = %s", (parsed_text[2], )) if len(results) <= 0: response["status"] = 210 return response recipient_info = { "username": parsed_text[2], "address": results[0][0], "minimum": -1, } response["status"] = 40 else: response["status"] = 999 return response # check the send amount is above the user minimum, if a username is provided # if it was just an address, this would be -1 if response["amount"] < recipient_info["minimum"]: update_history_notes(entry_id, "below user minimum") response["status"] = 180 response["minimum"] = recipient_info["minimum"] return response # send the nanos!! response["hash"] = send( sender_info["address"], sender_info["private_key"], response["amount"], recipient_info["address"], )["hash"] # Update the sql and send the PMs sql = ( "UPDATE history SET notes = %s, address = %s, username = %s, recipient_username = %s, " "recipient_address = %s, amount = %s, hash = %s, return_status = %s WHERE id = %s" ) val = ( "sent to user", sender_info["address"], sender_info["username"], recipient_info["username"], recipient_info["address"], str(response["amount"]), response["hash"], "cleared", entry_id, ) tipper_functions.exec_sql(sql, val) LOGGER.info( f"Sending Nano: {sender_info['address']} {sender_info['private_key']} {response['amount']} {recipient_info['address']} {recipient_info['username']}" ) # Update the sql and send the PMs if needed # if there is no private key, it's a donation. No PMs to send if "private_key" not in recipient_info.keys(): sql = "UPDATE history SET notes = %s, address = %s, username = %s, recipient_address = %s, amount = %s WHERE id = %s" val = ( "sent to nanocenter address", sender_info["address"], sender_info["username"], recipient_info["address"], str(response["amount"]), entry_id, ) tipper_functions.exec_sql(sql, val) response["status"] = 40 return response # update the sql database and send sql = ( "UPDATE history SET notes = %s, address = %s, username = %s, recipient_username = %s, " "recipient_address = %s, amount = %s, return_status = %s WHERE id = %s" ) val = ( "sent to user", sender_info["address"], sender_info["username"], recipient_info["username"], recipient_info["address"], str(response["amount"]), "cleared", entry_id, ) tipper_functions.exec_sql(sql, val) if response["status"] == 20: subject = "Congrats on receiving your first Nano Tip!" message_text = (text.WELCOME_TIP % ( response["amount"] / 10**30, recipient_info["address"], recipient_info["address"], ) + text.COMMENT_FOOTER) send_pm(recipient_info["username"], subject, message_text) return response else: if not recipient_info["silence"]: receiving_new_balance = check_balance(recipient_info["address"]) subject = "You just received a new Nano tip!" message_text = (text.NEW_TIP % ( response["amount"] / 10**30, recipient_info["address"], receiving_new_balance[0] / 10**30, receiving_new_balance[1] / 10**30, response["hash"], ) + text.COMMENT_FOOTER) send_pm(recipient_info["username"], subject, message_text) return response
def return_transactions(): LOGGER.info("Running inactive script") myresults = query_sql("SELECT username FROM accounts WHERE active IS NOT TRUE") inactivated_accounts = {item[0] for item in myresults} results = query_sql( "SELECT recipient_username FROM history WHERE action = 'send' " "AND hash IS NOT NULL " "AND `sql_time` <= SUBDATE( CURRENT_DATE, INTERVAL 31 DAY) " "AND (" "return_status = 'cleared' " "OR return_status = 'warned'" ")" ) tipped_accounts = {item[0] for item in results} tipped_inactivated_accounts = inactivated_accounts.intersection(tipped_accounts) LOGGER.info(f"Accounts on warning: {sorted(tipped_inactivated_accounts)}") returns = {} # scrolls through our inactive members and check if they have unclaimed tips for i, recipient in enumerate(tipped_inactivated_accounts): # send warning messages on day 31 sql = ( "SELECT id, username, amount FROM history WHERE action = 'send' " "AND hash IS NOT NULL " "AND recipient_username = %s " "AND `sql_time` <= SUBDATE( CURRENT_DATE, INTERVAL 31 DAY) " "AND return_status = 'cleared'" ) txns = query_sql(sql, (recipient,)) if len(txns) >= 1: LOGGER.info(f"Warning Message to {recipient}") send_pm(recipient, SUBJECTS["RETURN_WARNING"], RETURN_WARNING + HELP) for txn in txns: sql = "UPDATE history SET return_status = 'warned' WHERE id = %s" val = (txn[0],) exec_sql(sql, val) # return transactions over 35 days old sql = ( "SELECT id, username, amount FROM history WHERE action = 'send' " "AND hash IS NOT NULL " "AND recipient_username = %s " "AND `sql_time` <= SUBDATE( CURRENT_DATE, INTERVAL 35 DAY) " "AND return_status = 'warned'" ) val = (recipient,) txns = query_sql(sql, val) if len(txns) >= 1: sql = "SELECT address, private_key FROM accounts WHERE username = %s" inactive_results = query_sql(sql, (recipient,)) address = inactive_results[0][0] private_key = inactive_results[0][1] for txn in txns: # set the pre-update message to 'return failed'. This will be changed # to 'returned' upon success sql = "UPDATE history SET return_status = 'return failed' WHERE id = %s" val = (txn[0],) exec_sql(sql, val) # get the transaction information and find out to whom we are returning # the tip sql = "SELECT address, percentage FROM accounts WHERE username = %s" val = (txn[1],) returned_results = query_sql(sql, val) recipient_address = returned_results[0][0] percentage = returned_results[0][1] percentage = float(percentage) / 100 # send it back donation_amount = from_raw(int(txn[2])) donation_amount = donation_amount * percentage donation_amount = to_raw(donation_amount) return_amount = int(txn[2]) - donation_amount if (return_amount > 0) and (return_amount <= int(txn[2])): hash = send(address, private_key, return_amount, recipient_address)[ "hash" ] add_history_record( action="return", hash=hash, amount=return_amount, notes="Returned transaction from history record %s" % txn[0], ) if (donation_amount > 0) and (donation_amount <= int(txn[2])): hash2 = send( address, private_key, donation_amount, TIPBOT_DONATION_ADDRESS, )["hash"] add_history_record( action="donate", hash=hash2, amount=donation_amount, notes="Donation from returned tip %s" % txn[0], ) # update database if everything goes through sql = "UPDATE history SET return_status = 'returned' WHERE id = %s" val = (txn[0],) exec_sql(sql, val) # add transactions to the messaging queue to build a single message message_recipient = txn[1] if message_recipient not in returns.keys(): returns[message_recipient] = { "percent": round(percentage * 100, 2), "transactions": [], } returns[message_recipient]["transactions"].append( [ recipient, from_raw(int(txn[2])), from_raw(return_amount), from_raw(donation_amount), ] ) # send out our return messages for user in returns: message = text.make_return_message(returns[user]) send_pm(user, SUBJECTS["RETURN_MESSAGE"], message) LOGGER.info("Inactivated script complete.")
def send_from_comment(message): """ Error codes: Success 10 - sent to existing user 20 - sent to new user 30 - sent to address 40 - donated to nanocenter project Tip not sent 100 - sender account does not exist 110 - Amount and/or recipient not specified 120 - could not parse send amount 130 - below program minimum 150 - below 1 nano for untracked sub 160 - insufficient funds 170 - invalid address / recipient 180 - below recipient minimum 200 - No Nanocenter Project specified 210 - Nanocenter Project does not exist Extracts send command information from a PM command :param message: :return: response string """ parsed_text = parse_text(str(message.body)) response = {"username": str(message.author)} message_time = datetime.datetime.utcfromtimestamp( message.created_utc) # time the reddit message was created entry_id = add_history_record( username=response["username"], action="send", comment_or_message="comment", comment_id=message.name, reddit_time=message_time, comment_text=str(message.body)[:255], ) # don't do anything if the first word is a tip command or username if (parsed_text[0] in [f"/u/{TIP_BOT_USERNAME}", f"u/{TIP_BOT_USERNAME}" ]) or (parsed_text[0] in TIP_COMMANDS): pass # if the second to last is a username or tip command, redifine parsed text elif (parsed_text[-2] in [ f"/u/{TIP_BOT_USERNAME}", f"u/{TIP_BOT_USERNAME}" ]) or (parsed_text[-2] in TIP_COMMANDS): parsed_text = parsed_text[-2:] # before we can do anything, check the subreddit status for generating the response response["subreddit"] = str(message.subreddit).lower() try: sr = Subreddit.select(Subreddit.status, Subreddit.minimum).where( Subreddit.subreddit == response["subreddit"]).get() response["subreddit_status"] = sr.status response["subreddit_minimum"] = sr.minimum except Subreddit.DoesNotExist: response["subreddit_status"] = "untracked" response["subreddit_minimum"] = "1" if parsed_text[0] in TIP_COMMANDS and len(parsed_text) <= 1: update_history_notes(entry_id, "no recipient or amount specified") response["status"] = 110 return response # pull sender account info sender_info = tipper_functions.account_info(response["username"]) if not sender_info: update_history_notes(entry_id, "user does not exist") response["status"] = 100 return response # parse the amount try: response["amount"] = parse_raw_amount(parsed_text, response["username"]) except TipError as err: response["status"] = 120 response["amount"] = parsed_text[1] update_history_notes(entry_id, err.sql_text) return response # check if it's above the program minimum if response["amount"] < to_raw(PROGRAM_MINIMUM): update_history_notes(entry_id, "amount below program limit") response["status"] = 130 return response # check the user's balance if response["amount"] > sender_info["balance"]: update_history_notes(entry_id, "insufficient funds") response["status"] = 160 return response # check that it's above the subreddit minimum if response["amount"] < to_raw(response["subreddit_minimum"]): update_history_notes(entry_id, "amount below subreddit minimum") response["status"] = 150 return response # if it's a normal send, pull the account author # we will distinguish users from donations by the presence of a private key if parsed_text[0] in (TIP_COMMANDS + [f"/u/{TIP_BOT_USERNAME}", f"u/{TIP_BOT_USERNAME}"]): response["status"] = 10 response["recipient"] = str(message.parent().author) recipient_info = tipper_functions.account_info(response["recipient"]) if not recipient_info: response["status"] = 20 recipient_info = tipper_functions.add_new_account( response["recipient"]) if recipient_info is None: return text.TIP_CREATE_ACCT_ERROR elif recipient_info["silence"]: response["status"] = 11 elif not recipient_info["opt_in"]: response["status"] = 190 return response else: response["status"] = 999 return response if sender_info["address"] == recipient_info["address"]: # Don't allow sends to yourself response["status"] = 200 return response # send the bans!! response["hash"] = send( sender_info["address"], response["amount"], recipient_info["address"], )["block"] # Update the sql and send the PMs History.update( notes="sent to user", address=sender_info["address"], username=sender_info["username"], recipient_username=recipient_info["username"], recipient_address=recipient_info["address"], amount=str(response["amount"]), hash=response["hash"], return_status="cleared").where(History.id == entry_id).execute() LOGGER.info( f"Sending Banano: {sender_info['address']} {sender_info['private_key']} {response['amount']} {recipient_info['address']} {recipient_info['username']}" ) if response["status"] == 20: subject = text.SUBJECTS["first_tip"] message_text = (text.WELCOME_TIP % ( NumberUtil.format_float(from_raw(response["amount"])), recipient_info["address"], recipient_info["address"], ) + text.COMMENT_FOOTER) send_pm(recipient_info["username"], subject, message_text) return response else: if not recipient_info["silence"]: receiving_new_balance = check_balance(recipient_info["address"]) subject = text.SUBJECTS["new_tip"] message_text = (text.NEW_TIP % ( NumberUtil.format_float(from_raw(response["amount"])), recipient_info["address"], from_raw(receiving_new_balance), response["hash"], ) + text.COMMENT_FOOTER) send_pm(recipient_info["username"], subject, message_text) return response
def handle_send(message): """ Extracts send command information from a PM command :param message: :return: """ parsed_text = parse_text(str(message.body)) username = str(message.author) message_time = datetime.utcfromtimestamp( message.created_utc) # time the reddit message was created entry_id = add_history_record( username=username, action="send", comment_or_message="message", comment_id=message.name, reddit_time=message_time, comment_text=str(message.body)[:255], ) response = {"username": username} # check that there are enough fields (i.e. a username) if len(parsed_text) <= 2: update_history_notes(entry_id, "no recipient or amount specified") response["status"] = 110 return response # pull sender account info sender_info = tipper_functions.account_info(response["username"]) if not sender_info: update_history_notes(entry_id, "user does not exist") response["status"] = 100 return response # parse the amount try: response["amount"] = parse_raw_amount(parsed_text, response["username"]) except TipError as err: response["status"] = 120 response["amount"] = parsed_text[1] update_history_notes(entry_id, err.sql_text) return response # check if it's above the program minimum if response["amount"] < to_raw(PROGRAM_MINIMUM): update_history_notes(entry_id, "amount below program limit") response["status"] = 130 return response # check the user's balance if response["amount"] > sender_info["balance"]: update_history_notes(entry_id, "insufficient funds") response["status"] = 160 return response recipient_text = parsed_text[2] # catch invalid redditor AND address try: recipient_info = parse_recipient_username(recipient_text) except TipError as err: update_history_notes(entry_id, err.sql_text) response["recipient"] = recipient_text response["status"] = 170 return response # if we have a username, pull their info if "username" in recipient_info.keys(): response["recipient"] = recipient_info["username"] recipient_name = recipient_info["username"] recipient_info = tipper_functions.account_info(recipient_name) response["status"] = 10 if recipient_info is None: recipient_info = tipper_functions.add_new_account( response["recipient"]) if recipient_info is None: return text.TIP_CREATE_ACCT_ERROR response["status"] = 20 elif not recipient_info["opt_in"]: response["status"] = 190 return response # check if it's an address else: # otherwise, just use the address. Everything is None except address response["recipient"] = recipient_info["address"] response["status"] = 30 if sender_info["address"] == recipient_info["address"]: # Don't allow sends to yourself response["status"] = 200 return response response["hash"] = send( sender_info["address"], response["amount"], recipient_info["address"], )["block"] # if it was an address, just send to the address if "username" not in recipient_info.keys(): History.update( notes="send to address", address=sender_info["address"], username=sender_info["username"], recipient_username=None, recipient_address=recipient_info["address"], amount=str(response["amount"]), return_status="cleared").where(History.id == entry_id).execute() LOGGER.info( f"Sending Banano: {sender_info['address']} {sender_info['private_key']} {response['amount']} {recipient_info['address']}" ) return response # Update the sql and send the PMs History.update( notes="send to address", address=sender_info["address"], username=sender_info["username"], recipient_username=recipient_info["username"], recipient_address=recipient_info["address"], amount=str(response["amount"]), return_status="cleared").where(History.id == entry_id).execute() LOGGER.info( f"Sending Banano: {sender_info['address']} {sender_info['private_key']} {response['amount']} {recipient_info['address']} {recipient_info['username']}" ) if response["status"] == 20: subject = text.SUBJECTS["first_tip"] message_text = (WELCOME_TIP % ( NumberUtil.format_float(from_raw(response["amount"])), recipient_info["address"], recipient_info["address"], ) + COMMENT_FOOTER) send_pm(recipient_info["username"], subject, message_text) return response else: if not recipient_info["silence"]: receiving_new_balance = check_balance(recipient_info["address"]) subject = text.SUBJECTS["new_tip"] message_text = (NEW_TIP % ( NumberUtil.format_float(from_raw(response["amount"])), recipient_info["address"], from_raw(receiving_new_balance), response["hash"], ) + COMMENT_FOOTER) send_pm(recipient_info["username"], subject, message_text) return response
def return_transactions_new(): # remove all activated recipients LOGGER.info("Running inactive script") myresults = query_sql( "SELECT username FROM accounts WHERE active IS NOT TRUE") inactivated_accounts = {item[0] for item in myresults} myresults = query_sql("SELECT recipient_username FROM returns") return_accounts = {item[0] for item in myresults} # accounts which have been activated and should be removed from the returns accounts_to_remove = return_accounts - inactivated_accounts for account in accounts_to_remove: exec_sql("DELETE FROM returns WHERE recipient_username = %s", val=(account, )) # return accounts myresults = query_sql("SELECT recipient_username FROM returns") return_accounts = {item[0] for item in myresults} returns = {} # warn recipients for return_from in return_accounts: # return transactions over 35 days old sql = ( "SELECT id, username, amount, history_id FROM returns WHERE" " recipient_username = %s" " AND `sql_time` <= SUBDATE( CURRENT_TIMESTAMP, INTERVAL 35 DAY)" " AND return_status = 'warned'") val = (return_from, ) txns = query_sql(sql, val) # if there are transactions, do them if len(txns) > 0: sql = "SELECT address, private_key FROM accounts WHERE username = %s" inactive_results = query_sql(sql, (return_from, )) from_address = inactive_results[0][0] private_key = inactive_results[0][1] for txn in txns: # set the pre-update message to 'failed'. This will be # deleted upon success sql = "UPDATE returns SET return_status = 'failed' WHERE id = %s" val = (txn[0], ) exec_sql(sql, val) # get the transaction information and find out to whom we are returning sql = "SELECT address, percentage FROM accounts WHERE username = %s" val = (txn[1], ) returned_results = query_sql(sql, val) recipient_address = returned_results[0][0] percentage = returned_results[0][1] percentage = float(percentage) / 100 # send it back donation_amount = from_raw(int(txn[2])) donation_amount = donation_amount * percentage donation_amount = to_raw(donation_amount) return_amount = int(txn[2]) - donation_amount new_entry = 0 if (return_amount > 0) and (return_amount <= int(txn[2])): hash = send(from_address, private_key, return_amount, recipient_address)["hash"] new_entry = add_history_record( action="return", hash=hash, amount=return_amount, notes="Returned transaction from history record %s" % txn[3], username=txn[1], recipient_username=return_from, ) if (donation_amount > 0) and (donation_amount <= int(txn[2])): hash2 = send( from_address, private_key, donation_amount, TIPBOT_DONATION_ADDRESS, )["hash"] new_entry = add_history_record( action="donate", hash=hash2, amount=donation_amount, notes="Donation from returned tip %s" % txn[3], username=txn[1], recipient_username=return_from, ) # remove transactions from the return sql = "DELETE FROM returns WHERE id = %s" val = (txn[0], ) exec_sql(sql, val) # update database if everything goes through sql = f"UPDATE history SET return_status = 'returned by {new_entry}' WHERE id = %s" val = (txn[3], ) exec_sql(sql, val) # add transactions to the messaging queue to build a single message message_recipient = txn[1] if message_recipient not in returns.keys(): returns[message_recipient] = { "percent": round(percentage * 100, 2), "transactions": [], } returns[message_recipient]["transactions"].append([ return_from, from_raw(int(txn[2])), from_raw(return_amount), from_raw(donation_amount), ]) # send warning messages on day 31 sql = ( "SELECT id FROM returns WHERE" " recipient_username = %s" " AND `sql_time` <= SUBDATE( CURRENT_TIMESTAMP, INTERVAL 31 DAY)" " AND return_status = 'returnable'") txns = query_sql(sql, (return_from, )) if len(txns) >= 1: LOGGER.info(f"Warning Message to {return_from}") send_pm(return_from, SUBJECTS["RETURN_WARNING"], RETURN_WARNING + HELP) for txn in txns: sql = "UPDATE returns SET return_status = 'warned' WHERE id = %s" val = (txn[0], ) exec_sql(sql, val) # send out our return messages for user in returns: message = text.make_return_message(returns[user]) send_pm(user, SUBJECTS["RETURN_MESSAGE"], message) LOGGER.info("Inactivated script complete.")