async def cog_before_invoke(self, ctx: Context): ctx.error = False msg = ctx.message # Check paused if await RedisDB.instance().is_paused(): ctx.error = True await Messages.send_error_dm(msg.author, f"Transaction activity is currently suspended. I'll be back online soon!") return if ctx.command.name == 'send_cmd': try: ctx.send_amount = RegexUtil.find_send_amounts(msg.content) if Validators.too_many_decimals(ctx.send_amount): await Messages.send_error_dm(msg.author, f"You are only allowed to use {Env.precision_digits()} digits after the decimal.") ctx.error = True return except AmountMissingException: await Messages.send_usage_dm(msg.author, SEND_INFO) ctx.error = True return except AmountAmbiguousException: await Messages.send_error_dm(msg.author, "You can only specify 1 amount to send") ctx.error = True return if ctx.command.name in ['send_cmd', 'sendmax_cmd']: # See if user exists in DB user = await User.get_user(msg.author) if user is None: await Messages.send_error_dm(msg.author, f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started.") ctx.error = True return elif user.frozen: ctx.error = True await Messages.send_error_dm(msg.author, f"Your account is frozen. Contact an admin if you need further assistance.") return # Update name, if applicable await user.update_name(msg.author.name) ctx.user = user # See if they are spammin' withdraw_delay = await user.get_next_withdraw_s() if withdraw_delay > 0: await Messages.send_error_dm(msg.author, f"You need to wait {withdraw_delay}s before you can withdraw again") ctx.error = True return try: ctx.destination = RegexUtil.find_address_match(msg.content) except AddressMissingException: await Messages.send_usage_dm(msg.author, SEND_INFO) ctx.error = True return except AddressAmbiguousException: await Messages.send_error_dm(msg.author, "You can only specify 1 destination address") ctx.error = True return if not Validators.is_valid_address(ctx.destination): await Messages.send_error_dm(msg.author, "The destination address you specified is invalid") ctx.error = True return
def test_valid_address(self): # Null should always be false self.assertFalse(Validators.is_valid_address(None)) os.environ['BANANO'] = '1' # Valid self.assertTrue( Validators.is_valid_address( 'ban_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94xr' )) # Bad checksum self.assertFalse( Validators.is_valid_address( 'ban_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94xa' )) # Bad length self.assertFalse( Validators.is_valid_address( 'ban_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94x' )) del os.environ['BANANO'] # Valid self.assertTrue( Validators.is_valid_address( 'nano_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94xr' )) # Bad checksum self.assertFalse( Validators.is_valid_address( 'nano_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94xa' )) # Bad length self.assertFalse( Validators.is_valid_address( 'nano_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94x' )) # Valid self.assertTrue( Validators.is_valid_address( 'xrb_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94xr' )) # Bad checksum self.assertFalse( Validators.is_valid_address( 'xrb_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94xa' )) # Bad length self.assertFalse( Validators.is_valid_address( 'xrb_1bananobh5rat99qfgt1ptpieie5swmoth87thi74qgbfrij7dcgjiij94x' ))
async def cog_before_invoke(self, ctx: Context): ctx.error = False msg = ctx.message # See if user exists in DB user = await User.get_user(msg.author) if user is None: ctx.error = True await Messages.send_error_dm( msg.author, f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started." ) return elif user.frozen: ctx.error = True await Messages.send_error_dm( msg.author, f"Your account is frozen. Contact an admin if you need further assistance." ) return ctx.user = user # Update name if applicable await user.update_name(msg.author.name) # Special checks for tipfavorites if ctx.command.name == 'tipfavorites_cmd': # Check admins ctx.god = msg.author.id in config.Config.instance().get_admin_ids() ctx.admin = False author: discord.Member = msg.author for role in author.roles: if role.id in config.Config.instance().get_admin_roles(): ctx.admin = True break # Check paused if await RedisDB.instance().is_paused(): ctx.error = True await Messages.send_error_dm( msg.author, f"Transaction activity is currently suspended. I'll be back online soon!" ) return # See if amount meets tip_minimum requirement try: send_amount = RegexUtil.find_float(msg.content) if send_amount < Constants.TIP_MINIMUM: raise AmountMissingException( f"Tip amount is too low, minimum is {Constants.TIP_MINIMUM}" ) elif Validators.too_many_decimals(send_amount): await Messages.send_error_dm( ctx.message.author, f"You are only allowed to use {Env.precision_digits()} digits after the decimal." ) ctx.error = True return except AmountMissingException: ctx.error = True await Messages.send_usage_dm(msg.author, TIPFAVORITES_INFO) ctx.send_amount = send_amount
def test_too_many_decimalse(self): os.environ['BANANO'] = '1' self.assertTrue(Validators.too_many_decimals(1.234)) self.assertFalse(Validators.too_many_decimals(1.23)) self.assertFalse(Validators.too_many_decimals(1.2)) del os.environ['BANANO'] self.assertTrue(Validators.too_many_decimals(1.2345678)) self.assertFalse(Validators.too_many_decimals(1.233456)) self.assertFalse(Validators.too_many_decimals(1.2))
async def cog_before_invoke(self, ctx: Context): ctx.error = False msg = ctx.message if ChannelUtil.is_private(ctx.message.channel): ctx.error = True return else: # Check admins ctx.god = msg.author.id in config.Config.instance().get_admin_ids() ctx.admin = False author: discord.Member = msg.author for role in author.roles: if role.id in config.Config.instance().get_admin_roles(): ctx.admin = True break # Check paused if await RedisDB.instance().is_paused(): ctx.error = True await Messages.send_error_dm( msg.author, f"Transaction activity is currently suspended. I'll be back online soon!" ) return # Check anti-spam if not ctx.god and await RedisDB.instance().exists( f"rainspam{msg.author.id}"): ctx.error = True await Messages.add_timer_reaction(msg) await Messages.send_basic_dm( msg.author, "You can only rain once every 5 minutes") return # Parse some info try: ctx.send_amount = RegexUtil.find_send_amounts(msg.content) if Validators.too_many_decimals(ctx.send_amount): await Messages.add_x_reaction(msg) await Messages.send_error_dm( msg.author, f"You are only allowed to use {Env.precision_digits()} digits after the decimal." ) ctx.error = True return elif ctx.send_amount < config.Config.instance().get_rain_minimum(): ctx.error = True await Messages.add_x_reaction(msg) await Messages.send_usage_dm(msg.author, RAIN_INFO) return # See if user exists in DB user = await User.get_user(msg.author) if user is None: await Messages.add_x_reaction(msg) await Messages.send_error_dm( msg.author, f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started." ) ctx.error = True return elif user.frozen: ctx.error = True await Messages.add_x_reaction(msg) await Messages.send_error_dm( msg.author, f"Your account is frozen. Contact an admin if you need further assistance." ) return # Update name, if applicable await user.update_name(msg.author.name) ctx.user = user except AmountMissingException: await Messages.add_x_reaction(msg) await Messages.send_usage_dm(msg.author, RAIN_INFO) ctx.error = True return except AmountAmbiguousException: await Messages.add_x_reaction(msg) await Messages.send_error_dm( msg.author, "You can only specify 1 amount to send") ctx.error = True return
async def giveaway_cmd(self, ctx: Context): if ctx.error: return msg = ctx.message user = ctx.user # Check paused if await RedisDB.instance().is_paused(): await Messages.send_error_dm(msg.author, f"Transaction activity is currently suspended. I'll be back online soon!") return # Check roles if not await self.role_check(msg): return elif msg.channel.id in config.Config.instance().get_no_spam_channels(): await Messages.send_error_dm(msg.author, f"You can't start giveaways in this channel") return if 'fee=' not in msg.content or 'duration=' not in msg.content: await Messages.send_usage_dm(msg.author, START_GIVEAWAY_INFO) await Messages.add_x_reaction(msg) return # Parse message split_content = msg.content.split(' ') cleaned_content = msg.content for split in split_content: if split.startswith('fee='): cleaned_content.replace(split, "") split = split.replace('fee=','').strip() if not split: continue try: fee = abs(float(split)) except ValueError as e: await Messages.add_x_reaction(msg) await Messages.send_usage_dm(msg.author, START_GIVEAWAY_INFO) return elif split.startswith('duration='): cleaned_content.replace(split, "") split=split.replace('duration=','').strip() if not split: continue try: duration = abs(int(split)) if not ctx.god and (duration < config.Config.instance().get_giveaway_min_duration() or duration > config.Config.instance().get_giveaway_max_duration()): raise ValueError("Bad duration specified") except ValueError as e: await Messages.add_x_reaction(msg) await Messages.send_usage_dm(msg.author, START_GIVEAWAY_INFO) return # Find giveaway amount try: giveaway_amount = RegexUtil.find_float(cleaned_content) if Validators.too_many_decimals(giveaway_amount): await Messages.send_error_dm(ctx.message.author, f"You are only allowed to use {Env.precision_digits()} digits after the decimal for giveaway amount.") ctx.error = True return elif fee > giveaway_amount * config.Config.instance().get_giveaway_max_fee_multiplier(): await Messages.add_x_reaction(msg) await Messages.send_usage_dm(msg.author, START_GIVEAWAY_INFO) return elif giveaway_amount < config.Config.instance().get_giveaway_minimum(): await Messages.add_x_reaction(msg) await Messages.send_usage_dm(msg.author, START_GIVEAWAY_INFO) return except AmountMissingException: await Messages.add_x_reaction(msg) await Messages.send_usage_dm(msg.author, START_GIVEAWAY_INFO) return # See how much they need to make this tip. available_balance = Env.raw_to_amount(await user.get_available_balance()) if giveaway_amount > available_balance: await Messages.add_x_reaction(ctx.message) await Messages.send_error_dm(msg.author, f"Your balance isn't high enough to start this giveaway. You have **{available_balance} {Env.currency_symbol()}**, but this tip would cost you **{giveaway_amount} {Env.currency_symbol()}**") return try: # Lock this so concurrent giveaways can't be started/avoid race condition async with RedisLock( await RedisDB.instance().get_redis(), key=f"{Env.currency_symbol().lower()}giveawaylock:{msg.guild.id}", timeout=30, wait_timeout=30 ) as lock: # See if giveaway already in progress active_giveaway = await Giveaway.get_active_giveaway(server_id=msg.guild.id) if active_giveaway is not None: await Messages.add_x_reaction(msg) await Messages.send_error_dm(msg.author, "There's already a giveaway in progress on this server") return # Start giveaway async with in_transaction() as conn: gw = await Giveaway.start_giveaway_user( server_id=msg.guild.id, started_by=user, amount=giveaway_amount, entry_fee=fee, duration=duration, started_in_channel=msg.channel.id, conn=conn ) # Create pending TX for this user await Transaction.create_transaction_giveaway( sending_user=user, amount=giveaway_amount, giveaway=gw, conn=conn ) # Announce giveaway embed = self.format_giveaway_announcement(gw) await msg.channel.send(embed=embed) for ch in config.Config.instance().get_giveaway_announce_channels(): if ch != msg.channel.id: channel = msg.guild.get_channel(ch) if channel is not None: try: await channel.send(embed=embed) except Exception: pass # Start the timer asyncio.create_task(self.start_giveaway_timer(gw)) except LockTimeoutError: await Messages.add_x_reaction(msg) await Messages.send_error_dm(msg.author, "I couldn't start a giveaway, maybe someone else beat you to it as there can only be 1 active at a time.")
async def cog_before_invoke(self, ctx: Context): ctx.error = False # Remove duplicate mentions ctx.message.mentions = set(ctx.message.mentions) # Only allow tip commands in public channels msg = ctx.message if ChannelUtil.is_private(msg.channel): ctx.error = True return else: # Check admins ctx.god = msg.author.id in config.Config.instance().get_admin_ids() ctx.admin = False author: discord.Member = msg.author for role in author.roles: if role.id in config.Config.instance().get_admin_roles(): ctx.admin = True break # Check paused if await RedisDB.instance().is_paused(): ctx.error = True await Messages.send_error_dm( msg.author, f"Transaction activity is currently suspended. I'll be back online soon!" ) return # See if user exists in DB user = await User.get_user(msg.author) if user is None: ctx.error = True await Messages.send_error_dm( msg.author, f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started." ) return elif user.frozen: ctx.error = True await Messages.send_error_dm( msg.author, f"Your account is frozen. Contact an admin if you need further assistance." ) return # Update name, if applicable await user.update_name(msg.author.name) ctx.user = user # See if amount meets tip_minimum requirement try: send_amount = RegexUtil.find_float(msg.content) if ctx.command.name == 'tiprandom_cmd' and send_amount < Constants.TIPRANDOM_MINIMUM: raise AmountMissingException( f"Tip random amount is too low, minimum is {Constants.TIPRANDOM_MINIMUM}" ) elif ctx.command.name != 'tiprandom_cmd' and ctx.command.name != 'burn' and send_amount < Constants.TIP_MINIMUM: raise AmountMissingException( f"Tip amount is too low, minimum is {Constants.TIP_MINIMUM}" ) elif ctx.command.name == 'burn' and send_amount < 1.0: raise AmountMissingException(f"Come on, burn at least 1 BAN") elif Validators.too_many_decimals(send_amount): await Messages.send_error_dm( ctx.message.author, f"You are only allowed to use {Env.precision_digits()} digits after the decimal." ) ctx.error = True return except AmountMissingException: ctx.error = True if ctx.command.name == 'tip_cmd': await Messages.send_usage_dm(msg.author, TIP_INFO) elif ctx.command.name == 'tipsplit_cmd': await Messages.send_usage_dm(msg.author, TIPSPLIT_INFO) elif ctx.command.name == 'tiprandom_cmd': await Messages.send_usage_dm(msg.author, TIPRANDOM_INFO) elif ctx.command.name == 'burn': await Messages.send_basic_dm( msg.author, 'Come on, burn at least 1 ya cheap skate') return ctx.send_amount = send_amount