def send_bis_to(self, amount, recipient, data='', operation='', check_balance=False): """ Sends BIS from current wallet to recipient, with optional data and operation If check_balance, checks the user balance is enough. Returns a dict with keys txid (txid if sudccess or None) and error ('', 'NO_WALLET','LOW_BALANCE','MP_INSERT') """ error = '' txid = None if path.isfile(self.wallet_file): BISMUTH_CLIENT.load_wallet(self.wallet_file) if check_balance: balance = BISMUTH_CLIENT.balance(for_display=False) fees = BismuthUtil.fee_for_tx(data) if float(balance) < float(amount) + fees: # TODO: better use an enum error = 'LOW_BALANCE' return {'txid': txid, 'error': error} txid = BISMUTH_CLIENT.send(recipient, amount, data=data, operation=operation) if not txid: error = 'MP_INSERT' else: error = 'NO_WALLET' return {'txid': txid, 'error': error}
async def freebismuth(self, ctx, tweet_url: str): """Register your #Bismuth tweet and get free bismuth""" try: amount = float(0) # amount has to be 0 operation = 'twitter' user = User(ctx.author.id) user_info = user.info() address = user_info['address'] #validate tweet url. # TODO: Validate tweet likes and retweets as per freebismuth spec if not validators.url(tweet_url): print("tweet url error") await ctx.message.add_reaction('😟') await ctx.send( "Link to the tweet does not look ok. Command is `Pawer freebismuth <tweet_url>`" ) return if user_info and user_info['address']: # User exists and validated the terms, has an address # Make sure balance is enough balance = float(user.balance()) tweet_id = re.search('/status/(\d+)', tweet_url).group(1) # Extract tweet ID msg = "{} freebismuth, tweet ID is {} ".format( ctx.author.display_name, tweet_id) fees = BismuthUtil.fee_for_tx(tweet_id) print(msg) if balance < amount + fees: print("balance too low") await ctx.message.add_reaction('😟') await ctx.send( "Not enough balance to cover fee ({} Fees)".format( fees)) return send = user.send_bis_to(amount, address, data=tweet_id, operation=operation) txid = send['txid'] print("txid", txid) if txid: # answer by reaction not to pollute await ctx.message.add_reaction('👍') # Thumb up await ctx.send( "Your tweet has been registered. Txid is {}.".format( txid)) else: await ctx.message.add_reaction('👎') # Thumb down await ctx.send( "Can't register your tweet. Error {}".format( send['error'])) return except Exception as e: print(str(e)) # Send a PM to the sender or answer if dedicated channel await ctx.message.add_reaction('👎') # Thumb down await ctx.send("Can't register your tweet. Error {}".format(e))
async def operation(self, ctx, operation: str, address: str, amount: str, message: str = ''): # TODO: too much code in common with withdraw, factorize somehow. try: amount = float(amount) user = User(ctx.message.author.id) user_info = user.info() # Check the address looks ok if not BismuthUtil.valid_address(address): print("address error") await self.bot.add_reaction(ctx.message, '😟') await self.bot.say( "Address does not look ok. Command is `Pawer operation <operation> <address> <amount> [message]`" ) return if user_info and user_info['address']: # User exists and validated the terms, has an address # Make sure balance is enough balance = float(user.balance()) msg = "{} withdraw {}, balance is {} ".format( ctx.message.author.display_name, amount, balance) fees = BismuthUtil.fee_for_tx(message) print(msg) if balance < amount + 0.01: print("balance too low") await self.bot.add_reaction(ctx.message, '😟') await self.bot.say( "Not enough balance to cover amount + fee ({} Fees)". format(fees)) return send = user.send_bis_to(amount, address, data=message, operation=operation) txid = send['txid'] print("txid", txid) if txid: # answer by reaction not to pollute await self.bot.add_reaction(ctx.message, '👍') # Thumb up await self.bot.say("Done, txid is {}.".format(txid)) else: await self.bot.add_reaction(ctx.message, '👎') # Thumb down await self.bot.say("Error {}".format(send['error'])) return # Depending on channel, say or send PM em = discord.Embed(description=DISCLAIMER, colour=discord.Colour.red()) em.set_author(name="You have to create your address first:") await self.bot.say(embed=em) except Exception as e: print(str(e)) # Send a PM to the sender or answer if dedicated channel await self.bot.add_reaction(ctx.message, '👎') # Thumb down await self.bot.say("Error {}".format(e))
async def withdraw(self, ctx, address: str, amount: str, *message): """Send BIS from your wallet to any BIS address, with an optional message""" try: amount = float(amount) openfield_data = ' '.join(filter(None, message)) user = User(ctx.author.id) user_info = user.info() # Check the address looks ok if not BismuthUtil.valid_address(address): print("address error") await ctx.message.add_reaction('😟') await ctx.send( "Address does not look ok. Command is `Pawer withdraw <address> <amount> [message]`" ) return if user_info and user_info['address']: # User exists and validated the terms, has an address # Make sure balance is enough balance = float(user.balance()) msg = "{} withdraw {}, balance is {} ".format( ctx.author.display_name, amount, balance) fees = BismuthUtil.fee_for_tx(openfield_data) print(msg) if balance < amount + 0.01: print("balance too low") await ctx.message.add_reaction('😟') await ctx.send( "Not enough balance to cover amount + fee ({} Fees)". format(fees)) return send = user.send_bis_to(amount, address, data=openfield_data) txid = send['txid'] print("txid", txid) if txid: # answer by reaction not to pollute await ctx.message.add_reaction('👍') # Thumb up await ctx.send("Done, txid is {}.".format(txid)) else: await ctx.message.add_reaction('👎') # Thumb down await ctx.send("Error {}".format(send['error'])) return # Depending on channel, say or send PM em = discord.Embed(description=DISCLAIMER, colour=discord.Colour.red()) em.set_author(name="You have to create your address first:") await ctx.send(embed=em) except Exception as e: print(str(e)) # Send a PM to the sender or answer if dedicated channel await ctx.message.add_reaction('👎') # Thumb down await ctx.send("Error {}".format(e))
async def zirco(self, ctx, amount: str, bet: str): """Play ZircoDice from your pawer wallet, with any amount less than 100 along with your bet """ try: amount = float(amount) zirco_service_address = '340c195f768be515488a6efedb958e135150b2ef3e53573a7017ac7d' user = User(ctx.author.id) user_info = user.info() # Check the bet field if bet.lower() not in ('odd', 'even'): print("OpenField data error") await ctx.message.add_reaction('😟') await ctx.send("Your bet does not look ok. Command is `Pawer zirco <amount> <odd/even>`") return # Check the bet amount if (amount - float(100)) > 0.01 : print("Bet amount too high") await ctx.message.add_reaction('😟') await ctx.send("You are betting too high. Recommended amount is less than 100`") return if user_info and user_info['address']: # User exists and validated the terms, has an address # Make sure balance is enough balance = float(user.balance()) msg = "{} zirco {}, balance is {} ".format(ctx.author.display_name, amount, balance) fees = BismuthUtil.fee_for_tx(bet) print(msg) if balance < amount + 0.01004: print("balance too low") await ctx.message.add_reaction('😟') await ctx.send("Not enough balance to cover amount + fee ({} Fees)".format(fees)) return send = user.send_bis_to(amount, zirco_service_address, data=bet) txid = send['txid'] print("txid", txid) if txid: # answer by reaction not to pollute await ctx.message.add_reaction('👍') # Thumb up await ctx.send("Your bet has been placed. Txid is {}".format(txid)) await self.bot.remove_reaction(ctx.message, '⏳', self.bot.user) await self.get_zirco_status(ctx.author, txid) else: await ctx.message.add_reaction('👎') # Thumb down await ctx.send("Can't place your bet. Error {}".format(send['error'])) return except Exception as e: print(str(e)) # Send a PM to the sender or answer if dedicated channel await ctx.message.add_reaction('👎') # Thumb down await ctx.send("Can't place your bet. Error {}".format(e))
def execute(self, bot, update, args): if len(args) == 0: msg = f"Usage:\n{self.get_usage()}" update.message.reply_text(msg, parse_mode=ParseMode.MARKDOWN) return username = update.effective_user.username # Check if user has a wallet if not Bismuth.wallet_exists(username): msg = "Accept terms and create a wallet first with:\n/accept" update.message.reply_text(msg) return try: decode = BismuthUtil.read_url(args[0]) except Exception as e: msg = f"{emo.ERROR} Does not look like a proper BIS URL" update.message.reply_text(msg, parse_mode=ParseMode.MARKDOWN) logging.error(f"{msg}: {e}") return amount = float(decode['amount']) address = decode['recipient'] operation = decode['operation'] message = decode['openfield'] fees = BismuthUtil.fee_for_tx(message) # Check if provided address is valid if not BismuthUtil.valid_address(address): update.message.reply_text( text=f"{emo.ERROR} Provided address is not valid", parse_mode=ParseMode.MARKDOWN) return bisurl_id = self.unix_time() # Save transaction to database insert = self.get_resource("insert_bisurl.sql") self.execute_sql(insert, bisurl_id, username, address, amount, operation, message) msg = "Execute following transaction?\n\n" msg += "▸ Recipient: {}\n".format(address) msg += "▸ Amount: {:.2f} BIS\n".format(amount) msg += "▸ Operation: {}\n".format(operation) msg += "▸ Message: {}\n".format(message) msg += "▸ Fees: {} BIS\n".format(fees) update.message.reply_text(msg, reply_markup=self._keyboard(bisurl_id))
async def bisurl(self, ctx, bisurl: str, send: str = 'NO'): """Decode a transaction from a BIS URL. Append SEND to effectively send the tx.""" # TODO: too much code in common with withdraw, factorize somehow. try: try: decode = BismuthUtil.read_url(bisurl) except Exception as e: await ctx.message.add_reaction('😢') # Crying await ctx.send("Does not look like a proper BIS URL") return amount = float(decode['amount']) address = decode['recipient'] operation = decode['operation'] message = decode['openfield'] fees = BismuthUtil.fee_for_tx(message) decoded = "▸ Recipient: {}\n".format(address) decoded += "▸ Amount: {:.2f} $BIS\n".format(amount) decoded += "▸ Operation: {}\n".format(operation) decoded += "▸ Message: {}\n".format(message) decoded += "▸ Fees: {} $BIS\n".format(fees) if send == 'SEND': title = "Decoded BIS URL:" em = discord.Embed(description=decoded, colour=discord.Colour.green()) em.set_author(name=title) await ctx.send(embed=em) else: title = "Decoded BIS URL: (**not** sent)" decoded += " \nPaste this command again and append ` SEND` if you want to send that transaction.\n" em = discord.Embed(description=decoded, colour=discord.Colour.green()) em.set_author(name=title) await ctx.send(embed=em) return user = User(ctx.author.id) user_info = user.info() # Check the address looks ok if not BismuthUtil.valid_address(decode['recipient']): print("address error") await ctx.message.add_reaction('😟') await ctx.send( "Address does not look ok. Command is `Pawer operation <operation> <address> <amount> [message]`" ) return if user_info and user_info['address']: # User exists and validated the terms, has an address # Make sure balance is enough balance = float(user.balance()) msg = "{} withdraw {}, balance is {} ".format( ctx.author.display_name, amount, balance) fees = BismuthUtil.fee_for_tx(message) print(msg) if balance < amount + 0.01: print("balance too low") await ctx.message.add_reaction('😟') await ctx.send( "Not enough balance to cover amount + fee ({} Fees)". format(fees)) return send = user.send_bis_to(amount, address, data=message, operation=operation) txid = send['txid'] print("txid", txid) if txid: # answer by reaction not to pollute await ctx.message.add_reaction('👍') # Thumb up await ctx.send("Done, txid is {}.".format(txid)) else: await ctx.message.add_reaction('👎') # Thumb down await ctx.send("Error {}".format(send['error'])) return # Depending on channel, say or send PM em = discord.Embed(description=DISCLAIMER, colour=discord.Colour.red()) em.set_author(name="You have to create your address first:") await ctx.send(embed=em) except Exception as e: print(str(e)) # Send a PM to the sender or answer if dedicated channel await ctx.message.add_reaction('👎') # Thumb down await ctx.send("Error {}".format(e))
def execute(self, bot, update, args): user = update.effective_user.username if len(args) < 2 or len(args) > 4: update.message.reply_text(text=f"Usage:\n{self.get_usage()}", parse_mode=ParseMode.MARKDOWN) return address = args[0] amount = args[1] operation = "" if len(args) > 2: operation = args[2] data = "" if len(args) > 3: data = args[3] # Check if provided amount is valid if not utl.is_numeric(amount) or float(amount) < 0: update.message.reply_text( text=f"{emo.ERROR} Specified amount is not valid", parse_mode=ParseMode.MARKDOWN) return # Check if provided address is valid if not BismuthUtil.valid_address(address): update.message.reply_text( text=f"{emo.ERROR} Provided address is not valid", parse_mode=ParseMode.MARKDOWN) return # Check if user has a wallet if not Bismuth.wallet_exists(user): msg = "Accept terms and create a wallet first with:\n/accept" update.message.reply_text(msg) return message = update.message.reply_text(text=f"{emo.WAIT} Processing...", parse_mode=ParseMode.MARKDOWN) bis = Bismuth(user) bis.load_wallet() balance = bis.get_balance() total = float(amount) + BismuthUtil.fee_for_tx(data) # Check for sufficient funds if not utl.is_numeric(balance) or float(balance) < total: bot.edit_message_text(chat_id=message.chat_id, message_id=message.message_id, text=f"{emo.ERROR} Not enough funds") return try: # Execute withdrawing trx = bis.send(address, amount, operation, data) except Exception as e: error = f"Error withdrawing {amount} BIS " \ f"from @{user} " \ f"to {address} " \ f"with '{operation}' " \ f"and '{data}': {e}" logging.error(error) self.notify(error) trx = None if trx: logging.debug(f"Withdraw {amount} BIS " f"from @{user} " f"to {address} " f"with '{operation}' " f"and '{data}'") # Save withdrawing to database insert = self.get_resource("insert_withdraw.sql") self.execute_sql(insert, user, address, amount) url = f"{self.BLCK_EXPL_URL}{utl.encode_url(trx)}" # Send success message bot.edit_message_text( chat_id=message.chat_id, message_id=message.message_id, text=f"{emo.DONE} DONE!\n[View on Block Explorer]({url})\n" f"(Available after ~1 minute)", parse_mode=ParseMode.MARKDOWN) else: # Send error message bot.edit_message_text( chat_id=message.chat_id, message_id=message.message_id, text= f"{emo.ERROR} Withdrawing not executed. Something went wrong..." )