예제 #1
0
 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
예제 #2
0
 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'
         ))
예제 #3
0
    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
예제 #4
0
 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))
예제 #5
0
    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
예제 #6
0
    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.")
예제 #7
0
 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