async def balance(self, ctx): user_balances = self.backoffice.wallet_manager.get_balances(user_id=ctx.message.author.id) coin_data = self.backoffice.integrated_coins if user_balances: all_wallets = list(user_balances.keys()) # initiate Discord embed balance_embed = Embed(title=f":office_worker: Wallet details for {ctx.message.author} :office_worker:", timestamp=datetime.utcnow(), colour=Colour.dark_orange()) balance_embed.set_thumbnail(url=ctx.message.author.avatar_url) for wallet_ticker in all_wallets: if wallet_ticker == 'xlm': coin_settings = coin_data[wallet_ticker] token_balance = get_normal(value=str(user_balances[wallet_ticker]), decimal_point=int(coin_settings["decimal"])) if coin_settings["coinGeckoListing"]: token_to_usd = convert_to_usd(amount=float(token_balance), coin_name='stellar') else: token_to_usd = {"total": 0, "usd": 0} balance_embed.add_field( name=f"{coin_settings['emoji']} {coin_settings['name']} Balance {coin_settings['emoji']}", value=f'{token_balance} {coin_settings["emoji"]} (${token_to_usd["total"]}) \n' f'Rate: ${token_to_usd["usd"]}/XLM', inline=False) await ctx.author.send(embed=balance_embed) else: title = '__Stellar Wallet Error__' message = f'Wallet could not be obtained from the system please try again later' await custom_messages.system_message(ctx=ctx, color_code=1, message=message, destination=1, sys_msg_title=title)
async def stream_transaction(self, ctx, recipient, tx_details: dict, message: str, tx_type: str): """ Send reports out to all destinations """ # Process message msg = process_message(message=message) # Send to channel where tx has been executed if tx_details['ticker'] == 'stellar': in_dollar = monetaryConversions.convert_to_usd(amount=tx_details["amount"], coin_name='stellar') tx_report_msg = f"{recipient.mention} member {ctx.message.author} just sent you {tx_details['amount']:.7f}" \ f" {tx_details['emoji']} (${in_dollar['total']:.4f})" explorer_msg = f'💵 {tx_details["amount"]:.7f} {CONST_STELLAR_EMOJI} (${in_dollar["total"]:.4f}) on ' \ f'{ctx.message.guild} channel {ctx.message.channel}' total_dollar_value = in_dollar['total'] conversion_rate = in_dollar["usd"] else: tx_report_msg = f"{recipient.mention} member {ctx.message.author} just sent you {tx_details['amount']}" \ f" {tx_details['emoji']}" explorer_msg = f'💵 {tx_details["amount"]} {tx_details["emoji"]} ({tx_details["ticker"]}) on ' \ f'{ctx.message.guild} channel {ctx.message.channel}' total_dollar_value = 0 conversion_rate = 0 await custom_messages.transaction_report_to_channel(ctx=ctx, message=tx_report_msg, tx_type=tx_type) tx_details["conversion"] = total_dollar_value tx_details["conversionRate"] = conversion_rate # report to sender await custom_messages.transaction_report_to_user(ctx=ctx, user=recipient, transaction_data=tx_details, destination=ctx.message.author, direction=0, tx_type=tx_type, message=msg) # report to recipient await custom_messages.transaction_report_to_user(ctx=ctx, user=ctx.message.author, transaction_data=tx_details, destination=recipient, direction=1, tx_type=tx_type, message=msg) # Send out explorer load_channels = [self.bot.get_channel(id=int(chn)) for chn in self.backoffice.guild_profiles.get_all_explorer_applied_channels()] await custom_messages.explorer_messages(applied_channels=load_channels, message=explorer_msg, tx_type=tx_type)
async def xlm(self, ctx, amount: float, address: str): """ Initiates withdrawal on Stellar chain :param ctx: Discord Context :param amount: Amount in Stellar :param address: Destination address of withdrawal :return: """ strip_address = address.strip() if self.help_functions.check_public_key(address=address) and not self.help_functions.check_for_special_char( string=strip_address): if strip_address != self.bot.backoffice.stellar_wallet.public_key: # Get the fee for stellar withdrawal stellar_fee = self.backoffice.bot_manager.get_fees_by_category(key='withdrawals')['fee_list']['xlm'] fee_in_stroops = int(stellar_fee * (10 ** 7)) xlm_minimum = integrated_coins['xlm']['minimumWithdrawal'] stroops_withdrawal = int(amount * (10 ** 7)) # Withdrawal amount request to stroops amount_major = stroops_withdrawal / (10 ** 7) # Withdrawal amount conversion to XLM # Check if minimum for withdrawal met if stroops_withdrawal >= xlm_minimum: # Calculate final amount to be withdrawn from users Wallet level 1 (db) # Deduct the fees from the amount final_stroop = stroops_withdrawal - fee_in_stroops final_normal = final_stroop / (10 ** 7) # Get user balance wallet_details = self.backoffice.wallet_manager.get_ticker_balance(ticker='xlm', user_id=ctx.message.author.id) # Check if user has sufficient balance to cover the withdrawal fee + amount if wallet_details >= stroops_withdrawal: # Confirmation message message_content = f":robot: {ctx.message.author.mention} Current withdrawal fee which will " \ f"be deducted from requested withdrawal amount is " \ f" {stellar_fee} {CONST_STELLAR_EMOJI}.\n " \ f"`Total {final_normal}XLM` \n" \ f"Please answer either with ***yes*** or ***no***." verification = await ctx.channel.send(content=message_content) msg_usr = await self.bot.wait_for('message', check=check(ctx.message.author)) if str(msg_usr.content.lower()) == 'yes': processing_msg = ':robot: Processing withdrawal request, please wait few moments....' processing_msg = await ctx.channel.send(content=processing_msg) to_deduct = { "xlm": int(final_stroop) * (-1) } # Withdraw balance from user wallet if self.backoffice.wallet_manager.update_user_balance_off_chain( user_id=ctx.message.author.id, coin_details=to_deduct): # Initiate on chain withdrawal result = self.backoffice.stellar_wallet.token_withdrawal(address=strip_address, token='xlm', amount=str(amount_major)) if result.get("hash"): # Store withdrawal details to database result['userId'] = int(ctx.message.author.id) result["time"] = int(time.time()) result['offChainData'] = {"xlmFee": stellar_fee} # Insert in the history of withdrawals await self.backoffice.stellar_manager.insert_to_withdrawal_hist(tx_type=1, tx_data=result) # Update user withdrawal stats withdrawal_data = { "xlm.withdrawalsCount": 1, "xlm.totalWithdrawn": round(stroops_withdrawal / (10 ** 7), 7), } await self.backoffice.stats_manager.update_usr_tx_stats( user_id=ctx.message.author.id, tx_stats_data=withdrawal_data) # Update bot stats bot_stats_data = { "withdrawalCount": 1, "withdrawnAmount": round(stroops_withdrawal / (10 ** 7), 7) } await self.backoffice.stats_manager.update_cl_on_chain_stats(ticker='xlm', stat_details=bot_stats_data) # Stores in earnings for tax office await self.backoffice.stats_manager.update_cl_earnings(time=int(time.time()), amount=fee_in_stroops, system='withdrawal', token="xlm", user=ctx.message.author.id) self.backoffice.bot_manager.update_cl_wallet_balance(ticker='xlm', to_update={'balance': int( fee_in_stroops)}) # Send message to user on withdrawal await custom_messages.withdrawal_notify(ctx, withdrawal_data=result, fee=f'{stellar_fee} XLM and') # # System channel notification on withdrawal processed channel_sys = self.bot.get_channel(id=int(self.with_channel)) await custom_messages.withdrawal_notification_channel(ctx=ctx, channel=channel_sys, withdrawal_data=result) # Notify staff on incoming funds incoming_funds = self.bot.get_channel( id=int(self.earnings)) await custom_messages.cl_staff_incoming_funds_notification( sys_channel=incoming_funds, incoming_fees=f'{stellar_fee} {CONST_STELLAR_EMOJI}') # Message to explorer in_dollar = convert_to_usd(amount=final_normal, coin_name='stellar') load_channels = [self.bot.get_channel(id=int(chn)) for chn in self.backoffice.guild_profiles.get_all_explorer_applied_channels()] explorer_msg = f':outbox_tray: {final_normal} {CONST_STELLAR_EMOJI} ' \ f'(${in_dollar["total"]}) on {ctx.message.guild}' await custom_messages.explorer_messages(applied_channels=load_channels, message=explorer_msg, tx_type='withdrawal', on_chain=True) else: message = 'Funds could not be withdrawn at this point. Please try again later.' # return user funds to off-chain wallet to_append = { "xlm": int(final_stroop) } self.backoffice.wallet_manager.update_user_balance_off_chain( user_id=ctx.message.author.id, coin_details=to_append) await custom_messages.system_message(ctx=ctx, color_code=1, message=message, destination=0, sys_msg_title=CONST_WITHDRAWAL_ERROR) else: message = 'Funds could not be withdrawn at this point. Please try again later.' await custom_messages.system_message(ctx=ctx, color_code=1, message=message, destination=0, sys_msg_title=CONST_WITHDRAWAL_ERROR) if isinstance(ctx.message.channel, TextChannel): await ctx.channel.delete_messages([processing_msg]) else: message = f'Withdrawal request has been cancelled' await custom_messages.system_message(ctx=ctx, color_code=1, message=message, destination=0, sys_msg_title=CONST_WITHDRAWAL_ERROR) if isinstance(ctx.message.channel, TextChannel): await ctx.channel.delete_messages([verification, msg_usr]) else: message = f'Amount you are willing to withdraw is greater than your current wallet balance' await custom_messages.system_message(ctx=ctx, color_code=1, message=message, destination=0, sys_msg_title=CONST_WITHDRAWAL_ERROR) else: message = f'Minimum amount to withdraw is set currently to {xlm_minimum / (10 ** 7)} ' \ f'{CONST_STELLAR_EMOJI}' await custom_messages.system_message(ctx=ctx, color_code=1, message=message, destination=0, sys_msg_title=CONST_WITHDRAWAL_ERROR) else: message = f'Withdrawal address you have provided matches the address of the hot wallet used for ' \ f'deposits. There is no sense to withdraw back ' \ f'to Discord wallet. ' await custom_messages.system_message(ctx=ctx, color_code=1, message=message, destination=0, sys_msg_title=CONST_WITHDRAWAL_ERROR) else: message = f"Withdrawal address ```{strip_address}``` is not a valid Stellar `Ed25519` Public Key." await custom_messages.system_message(ctx=ctx, color_code=1, message=message, destination=0, sys_msg_title=CONST_WITHDRAWAL_ERROR)