Exemple #1
0
    def MintNewHypeCoins(self):
        """Creates new HypeCoins if MINT_ACCOUNT is running low.

    Specifically, if the MINT_ACCOUNT has less than 25% of the total HypeCoin
    market size, this method will mint new coins scaling linearly with the
    number of users, and logarithmically with the total market size.
    """
        mint_balance = self.GetBalance(MINT_ACCOUNT)
        num_users, coins_in_circulation = self.GetBankStats()
        if mint_balance >= coins_in_circulation // 4:
            logging.info(
                'Mint balance (%s) >= 25%% of market (%s), not minting new coins',
                util_lib.FormatHypecoins(mint_balance),
                util_lib.FormatHypecoins(coins_in_circulation))
            return

        num_coins_to_mint = max(
            5000, int(math.log(coins_in_circulation, 2) * num_users * 1000))
        logging.info('Minting %s', util_lib.FormatHypecoins(num_coins_to_mint))
        entry = bank_pb2.LedgerEntry(counterparty={
            'user_id': '_ether',
            'display_name': 'Ether'
        },
                                     amount=num_coins_to_mint,
                                     details='Minting')
        entry.create_time.GetCurrentTime()
        if not self._Deposit(MINT_ACCOUNT, num_coins_to_mint, entry, None):
            logging.error('Minting %s failed',
                          util_lib.FormatHypecoins(num_coins_to_mint))
Exemple #2
0
    def SettleBets(self, pool, msg_fn, *args, **kwargs):
        # The lotto is global, so there should only be a single bet for each user
        pool_value = sum(user_bets[0].amount for user_bets in pool.values())
        if not pool_value:
            return ([], {})
        msg_fn(
            None, 'All 7-11s are closed! %s bet %s on the lottery' %
            (inflect_lib.Plural(len(pool),
                                'pleb'), util_lib.FormatHypecoins(pool_value)))

        coins, item = self.ComputeCurrentJackpot(pool)
        winning_number = random.randint(1, pool_value)
        ticket_number = 0
        for user, user_bets in pool.items():
            num_tickets = user_bets[0].amount
            ticket_number += num_tickets
            if ticket_number >= winning_number:
                msg_fn(user, [
                    'You\'ve won %s in the lottery!' %
                    util_lib.FormatHypecoins(coins),
                    ('We\'ve always been such close friends. Can I borrow some money '
                     'for rent?')
                ])
                msg_fn(
                    None, '%s won %s and a(n) %s in the lottery!' %
                    (user, util_lib.FormatHypecoins(coins), item.human_name))
                return ([(user, coins), (user, item)], {})

        return ([], {})
Exemple #3
0
    def SettleBets(self, pool, msg_fn, *args, **kwargs):
        unused_bets = defaultdict(list)
        winners = defaultdict(int)
        pool_value = 0
        msgs = []

        for user, user_bets in pool.items():
            winning_teams = []
            losing_teams = []
            net_amount = 0
            for bet in user_bets:
                lcs_data = bet_pb2.LCSData()
                bet.data.Unpack(lcs_data)
                match = self._esports.matches.get(bet.target, {})
                logging.info('Game time: %s', match)
                winner = match.get('winner', None)
                if winner:
                    logging.info('GambleLCS: %s bet %s for %s and %s won.',
                                 user, bet.amount, lcs_data.winner, winner)
                    pool_value += bet.amount
                    if lcs_data.winner == winner:
                        winning_teams.append(winner)
                        winners[user] += bet.amount * 2
                        net_amount += bet.amount
                    else:
                        losing_teams.append(lcs_data.winner)
                        net_amount -= bet.amount
                else:
                    logging.info('Unused bet: %s', bet)
                    unused_bets[user].append(bet)

            if winning_teams or losing_teams:
                right_snippet = _BuildSymbolSnippet(winning_teams, 'right')
                wrong_snippet = _BuildSymbolSnippet(losing_teams, 'wrong')

                if net_amount == 0:
                    summary_snippet = 'breaking even.'
                else:
                    summary_snippet = 'ending %s %s.' % (
                        'up' if net_amount > 0 else 'down',
                        util_lib.FormatHypecoins(abs(net_amount)))

                user_message = '%s was %s%s%s' % (
                    user, right_snippet, wrong_snippet, summary_snippet)
                msgs.append(user_message)

        if msgs:
            msg_fn(
                None, 'LCS match results in! %s bet %s.' % (inflect_lib.Plural(
                    len(msgs), 'pleb'), util_lib.FormatHypecoins(pool_value)))
        for msg in msgs:
            msg_fn(None, msg)

        return (winners.items(), unused_bets)
Exemple #4
0
  def _Deposit(self, user, num_coins, tx_details, msg_fn):
    """Adds num_coins to user's balance.

    Args:
      user: {string} name of account into which to deposit.
      num_coins: {int} number of hype coins to deposit.
      tx_details: {dict} details of transaction.
      msg_fn: {callable(channel, msg)} function to send messages.

    Returns:
      {boolean} whether deposit was successful.
    """
    if num_coins < 0:
      logging.error('Deposit called with negative value: %s, %s', user,
                    num_coins)
      return False

    tx_details['type'] = 'deposit'
    tx_name = 'CREDIT %s %s' % (num_coins, user)
    self._store.RunInTransaction(
        self._BankTransaction, user, num_coins, tx_details, tx_name=tx_name)
    if msg_fn:
      msg_fn(user, '%s deposited into your account. (%s)' %
             (util_lib.FormatHypecoins(num_coins),
              tx_details.get('details', '')))
    # TODO(someone): Maybe fix returns now that RunInTransaction can throw.
    return True
Exemple #5
0
 def _Handle(self, channel: channel_pb2.Channel,
             user: user_pb2.User) -> hype_types.CommandResponse:
     num_users, coins_in_circulation = self._core.bank.GetBankStats(
         plebs_only=True)
     return ('There is %s circulating among %s.' %
             (util_lib.FormatHypecoins(coins_in_circulation),
              inflect_lib.Plural(num_users, 'pleb')))
Exemple #6
0
 def _Handle(self, channel: types.Channel, user: str):
     data = self._core.proxy.FetchJson(
         'https://kittysales.herokuapp.com/data', {
             'offset': 0,
             'count': 1
         },
         force_lookup=True)
     if data:
         totals = data['totals']
         num_kitties = util_lib.FormatHypecoins(totals['sales'], True)[:-1]
         usd = util_lib.FormatHypecoins(totals['usdSold'], True)[:-1]
         eth = util_lib.FormatHypecoins(totals['etherSold'], True)[:-1]
         return 'There have been %s cryptokitties sold for $%s [Ξ %s]' % (
             num_kitties, usd, eth)
     else:
         return 'I don\'t know right now, but we\'ll say, a lot.'
Exemple #7
0
    def _Handle(self, channel: channel_pb2.Channel,
                user: user_pb2.User) -> hype_types.CommandResponse:
        cur_balance = self._core.bank.GetBalance(user)
        if cur_balance > self._params.bailout_amount:
            return ('Surprisingly, I don\'t like to steal hypecoins. '
                    'Your balance remains %s'
                    ) % util_lib.FormatHypecoins(cur_balance)

        bet_potential = 0
        for game in self._core.betting_games:
            game_bets = self._core.bets.LookupBets(game.name, user)
            for bet in game_bets.get(user.user_id, []):
                bet_potential += bet.amount * 2
        if cur_balance + bet_potential > self._params.bailout_amount:
            return 'You have great potential with your current bets.'

        if cur_balance <= 0:
            self._Reply(
                channel,
                f'{user.display_name} has been foolish and unwise with their '
                'HypeCoins.')
        bailout_amount = self._params.bailout_amount - (cur_balance +
                                                        bet_potential)
        if not self._core.bank.ProcessPayment(coin_lib.MINT_ACCOUNT, user,
                                              bailout_amount, 'Bailout',
                                              self._Reply):
            return messages.HYPECOIN_MINT_EXHAUSTION_STR
Exemple #8
0
  def _Handle(self, channel, user, account, tx_user):
    tx_user = tx_user or user
    if tx_user == 'me':
      tx_user = user
    tx_user = _GetUserAccount(tx_user, account)
    now = arrow.utcnow()
    recent_transactions = self._core.bank.GetTransactions(tx_user)
    if not recent_transactions:
      return '%s doesn\'t believe in the HypeCoin economy.' % tx_user

    responses = ['Recent HypeCoin Transactions for %s' % tx_user]
    for tx in recent_transactions[:5]:
      if tx_user == tx.get('source'):
        base_tx_description = ' {} to {} %s ago [%s]'.format(
            util_lib.Colorize('-%s', 'red'), tx.get('destination', 'unknown'))
      else:
        base_tx_description = ' {} from {} %s ago [%s]'.format(
            util_lib.Colorize('+%s', 'green'), tx.get('source', 'unknown'))

      time_delta = now - arrow.get(tx.get('ts', now.timestamp))
      time_str = util_lib.TimeDeltaToHumanDuration(
          time_delta) if time_delta else '??'

      tx_description = base_tx_description % (
          util_lib.FormatHypecoins(tx['amount']), time_str,
          tx.get('details', 'Unknown'))
      responses.append(tx_description)
    return responses
Exemple #9
0
    def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User,
                target_user: user_pb2.User) -> hype_types.CommandResponse:
        now = arrow.utcnow()
        recent_transactions = self._core.bank.GetTransactions(target_user)
        if not recent_transactions:
            return '%s doesn\'t believe in the HypeCoin economy.' % target_user.display_name

        responses = [
            'Recent HypeCoin Transactions for %s' % target_user.display_name
        ]
        for tx in recent_transactions[:5]:
            amount = util_lib.FormatHypecoins(tx.amount)
            if tx.amount < 0:
                amount = util_lib.Colorize(f'{amount}', 'red')
                direction = 'to'
            elif tx.amount > 0:
                amount = util_lib.Colorize(f'+{amount}', 'green')
                direction = 'from'
            else:
                amount = amount
                direction = 'with'

            ago = util_lib.TimeDeltaToHumanDuration(
                now - arrow.get(tx.create_time.ToSeconds()))
            responses.append(
                f'{amount} {direction} {tx.counterparty.display_name} '
                f'{ago} ago [{tx.details}]')
        return responses
Exemple #10
0
  def _Handle(self, channel, user, account, recipient, amount_str='1'):
    if (account or coin_lib.IsSubAccount(user) or
        coin_lib.IsSubAccount(recipient)):
      return 'You cannot gift to/from sub-accounts.'
    self._core.last_command = partial(self._Handle,
                                      account=account,
                                      recipient=recipient,
                                      amount_str=amount_str)

    if user in coin_lib.HYPECENTS:
      return '%s is not a candy machine.' % user

    msg_fn = partial(self._Reply, default_channel=channel)
    amount = self._core.bank.ParseAmount(user, amount_str, msg_fn)
    if amount is None:
      return
    if amount <= 0:
      return 'Wow, much gift, so big!'

    normalized_recipient = recipient.lower()

    if normalized_recipient == self._core.nick:
      self._Reply(channel, messages.OH_STRING)

    if normalized_recipient in self._UNGIFTABLE:
      return

    if self._core.bank.ProcessPayment(
        user, recipient, amount, 'Gift', msg_fn):
      return '%s gave %s %s' % (user, recipient,
                                util_lib.FormatHypecoins(amount))
    else:
      return 'Gift failed. Are you actually scrooge?'
Exemple #11
0
    def _Deposit(self, user: user_pb2.User, num_coins: int,
                 entry: bank_pb2.LedgerEntry, msg_fn) -> bool:
        """Adds num_coins to user's balance.

    Args:
      user: User of account into which to deposit.
      num_coins: Number of hype coins to deposit.
      entry: Details of transaction.
      msg_fn: {callable(channel, msg)} function to send messages.

    Returns:
      Whether deposit was successful.
    """
        if num_coins < 0:
            logging.error('Deposit called with negative value: %s, %s', user,
                          num_coins)
            return False

        entry.amount = num_coins
        tx_name = 'CREDIT %s %s' % (num_coins, user.user_id)
        self._store.RunInTransaction(self._BankTransaction,
                                     user,
                                     num_coins,
                                     entry,
                                     tx_name=tx_name)
        if msg_fn:
            msg_fn(
                user, '%s deposited into your account. (%s)' %
                (util_lib.FormatHypecoins(num_coins), entry.details))
        # TODO: Maybe fix returns now that RunInTransaction can throw.
        return True
Exemple #12
0
 def _Handle(self, channel, unused_user):
   pool = self._core.bets.LookupBets(self._game.name, resolver=self._core.nick)
   jackpot, item = self._game.ComputeCurrentJackpot(pool)
   responses = ['Current jackpot is %s and a(n) %s' % (
       util_lib.FormatHypecoins(jackpot), item.human_name)]
   for bet_user, user_bets in pool.items():
     for bet in user_bets:
       responses.append(u'- %s, %s' % (bet_user, self._game.FormatBet(bet)))
   return responses
Exemple #13
0
  def Rob(self, thief, victim, amount, msg_fn):
    """Attempt a robbery."""
    if amount < 0:
      msg_fn(None, 'Did you mean !hc gift?')
      return

    if victim.lower() in self._protected_peeps:
      mafia_fee = max(amount, int(0.05 * self._bank.GetBalance(thief)))
      msg_fn(None, 'The Godfather protects his family.')
      self._bank.ProcessPayment(
          thief, self._bot_name, mafia_fee,
          'In Soviet Russia, %s steals from you.' % self._bot_name,
          msg_fn, can_overdraft=True)
      return

    victim_balance = self._bank.GetBalance(victim)
    if victim_balance <= 0:
      msg_fn(None, 'You cannot milk a dead cow.')
      return

    thief_alert = self._GetPDF('thief')[thief]
    victim_alert = self._GetPDF('victim')[victim]
    offset = self._BASE_BALANCE_PERCENT * (1 - thief_alert - victim_alert)
    failure_chance = self._Sigmoid(float(amount) / victim_balance, offset)

    rob_attempt_score = random.random()

    logging.info('(%s: %0.2f, %s: %0.2f) %s of %s attempt %0.2f >? %0.2f',
                 thief, thief_alert,
                 victim, victim_alert,
                 amount, victim_balance,
                 rob_attempt_score, failure_chance)

    if rob_attempt_score < failure_chance:
      self._bank.ProcessPayment(thief, SCHOLARSHIP_ACCOUNT,
                                min(self._bank.GetBalance(thief), amount),
                                'Victim scholarship fund', msg_fn)
      self._DistributeToPastVictims(msg_fn)
      if (rob_attempt_score < failure_chance * thief_alert /
          (thief_alert + victim_alert + 1e-6)):
        msg_fn(None, '%s is a known thief and was caught.' % thief)
      else:
        msg_fn(None, '%s is on high alert and caught %s.' % (victim, thief))
      return

    # TODO(someone): Fold ProcessPayment into the UpdateScores tx.
    # We don't worry about the victim having insufficient funds since there is a
    # 0% chance of stealing 100% of someone's money.
    if self._bank.ProcessPayment(victim, thief, amount,
                                 'Highway robbery', msg_fn):
      self._store.RunInTransaction(self._UpdateScores, thief, victim, amount)
      formatted_amount = util_lib.FormatHypecoins(amount)
      msg_fn(None, '%s stole %s from %s' % (thief, formatted_amount, victim))
      # We privmsg the victim to make sure they know who stole their hypecoins.
      msg_fn(victim, 'You\'ve been robbed! %s stole %s' % (thief,
                                                           formatted_amount))
Exemple #14
0
 def _HandleList(self, channel, user, all_greetings):
   msgs = [
       'You can purchase one of the following upgraded greetings from '
       '%s' % self._core.params.name
   ]
   for i, greeting in enumerate(all_greetings):
     msgs.append('  %sgreet %d [%s] - \'%s\'' %
                 (self.command_prefix, i,
                  util_lib.FormatHypecoins(greeting[0]), greeting[1]))
   return msgs
Exemple #15
0
  def _Handle(self, channel, user, account, me, users_or_games):
    game_names = {g.name.lower(): g for g in self._core.betting_games}
    desired_games = set()
    users = set()
    if me:
      users.add(_GetUserAccount(user, account))
    for user_or_game in (users_or_games or '').split():
      if user_or_game in game_names:
        desired_games.add(game_names[user_or_game])
      elif user_or_game == 'me':
        users.add(_GetUserAccount(user, account))
      else:
        users.add(_GetUserAccount(user_or_game, account))
    query_name = '%s%s%s' % (', '.join(users),
                             ' - ' if users and desired_games else '',
                             ', '.join([g.name for g in desired_games]))

    # Default behaviors if not specified.
    if not users:
      users = set([None])  # This will allow all users in a LookupBets.
    if not desired_games:
      desired_games = self._core.betting_games

    bets = []
    bet_total = 0
    for game in desired_games:
      for bet_user in users:
        bets_by_user = self._core.bets.LookupBets(game.name, bet_user)
        for u, user_bets in bets_by_user.items():
          if account and not coin_lib.IsSubAccount(u, account):
            continue
          for bet in user_bets:
            if len(users) > 1 or users == set([None]):
              bets.append((bet.amount, '- %s, %s' % (u, game.FormatBet(bet))))
            else:
              bets.append((bet.amount, '- %s' % game.FormatBet(bet)))
            bet_total += bet.amount
    bets.sort(key=lambda bet: bet[0], reverse=True)
    bets = [betstring for _, betstring in bets]

    if not bets:
      query_str = '%s has n' % query_name if query_name else 'N'
      return '%so current bets. Risk aversion is unbecoming' % query_str

    responses = ['%s current bets [%s, %s]' %
                 (query_name or 'All', inflect_lib.Plural(len(bets), 'bet'),
                  util_lib.FormatHypecoins(bet_total))]
    if (len(bets) > self._params.num_bets and
        channel.visibility == Channel.PUBLIC):
      responses.append('Only showing %d bets, addiction is no joke.' %
                       self._params.num_bets)
      bets = bets[:self._params.num_bets]

    responses.extend(bets)
    return responses
Exemple #16
0
    def _Withdraw(self,
                  user: user_pb2.User,
                  num_coins: int,
                  entry: bank_pb2.LedgerEntry,
                  msg_fn,
                  can_overdraft: bool = False) -> bool:
        """Subtracts num_coins from user's balance.

    Args:
      user: User of account from which to withdraw.
      num_coins: Number of hype coins to withdraw.
      entry: Details of transaction.
      msg_fn: {callable(channel, msg)} function to send messages.
      can_overdraft: Whether it is possible to overdraft the account. If True,
        the account balance can go negative and no fees will be charged. If
        False, the transaction will fail and an overdraft fee will be assessed
        if there are insufficient funds for the transaction.

    Returns:
      Whether withdrawal was successful.
    """
        if num_coins < 0:
            logging.error('Withdraw called with negative value: %s, %s', user,
                          num_coins)
            return False
        # TODO: This should really be a transaction.
        with self._withdraw_lock:
            balance = self.GetBalance(user)
            if balance < num_coins and not can_overdraft:
                logging.info('Overdraft: %s, %d > %d', user, num_coins,
                             balance)
                overdraft_fee = max(
                    self._MIN_OVERDRAFT_FEE,
                    int(balance * self._MAX_OVERDRAFT_FEE_PERCENT))
                self.ProcessPayment(user,
                                    FEE_ACCOUNT,
                                    overdraft_fee,
                                    'Overdraft fee',
                                    msg_fn,
                                    can_overdraft=True)
                return False

            entry.amount = -num_coins
            tx_name = 'DEBIT %s %s' % (num_coins, user.user_id)
            self._store.RunInTransaction(self._BankTransaction,
                                         user,
                                         -num_coins,
                                         entry,
                                         tx_name=tx_name)
            if msg_fn:
                msg_fn(
                    user, '%s withdrawn from your account. (%s)' %
                    (util_lib.FormatHypecoins(num_coins), entry.details))
        # TODO: Maybe fix returns now that RunInTransaction can throw.
        return True
Exemple #17
0
  def _Handle(self, channel, user, account, forbes_user):
    if forbes_user:
      if forbes_user == 'me':
        self._core.last_command = partial(self._Handle,
                                          account=account,
                                          forbes_user=forbes_user)
        forbes_user = user
      forbes_user = _GetUserAccount(forbes_user, account)
      balance = self._core.bank.GetBalance(forbes_user)
      for game in self._core.betting_games:
        game_bets = self._core.bets.LookupBets(game.name, forbes_user)
        for bet in game_bets.get(forbes_user, []):
          balance += bet.amount
      return ('%s has a net worth of %s' % (
          forbes_user, util_lib.FormatHypecoins(balance, abbreviate=True)))

    # Top 4 plebs by net worth.
    pleb_balances = defaultdict(int)
    pleb_balances.update(self._core.bank.GetUserBalances(plebs_only=True,
                                                         account=account))
    for game in self._core.betting_games:
      game_bets = self._core.bets.LookupBets(game.name)
      for pleb, pleb_bets in game_bets.items():
        if account and not coin_lib.IsSubAccount(pleb, account):
          continue
        for bet in pleb_bets:
          pleb_balances[pleb] += bet.amount
    pleb_balances = sorted(
        [(pleb, balance) for pleb, balance in pleb_balances.items()],
        key=lambda x: x[1],
        reverse=True)

    responses = ['Forbes 4:']
    position = 1
    prev_balance = -1
    for i, (pleb, balance) in enumerate(pleb_balances[:4]):
      if balance != prev_balance:
        position = i + 1
        prev_balance = balance
      responses.append('#{}: {:>6} - {}'.format(
          position, util_lib.FormatHypecoins(balance, abbreviate=True), pleb))
    return responses
Exemple #18
0
  def _Handle(self, channel, user, account, balance_user):
    balance_user = balance_user or user
    if balance_user == 'me':
      self._core.last_command = partial(self._Handle,
                                        account=account,
                                        balance_user=balance_user)
      balance_user = user
    balance_user = _GetUserAccount(balance_user, account)

    balance = self._core.bank.GetBalance(balance_user)
    return '%s has %s' % (balance_user, util_lib.FormatHypecoins(balance))
Exemple #19
0
 def _LotteryWarningCallback(self, remaining=None):
   logging.info('Running lottery warning callback.')
   warning_str = ''
   if remaining is not None:
     warning_str += 'The lottery winner will be drawn in %s! ' % (
         util_lib.TimeDeltaToHumanDuration(remaining))
   pool = self._core.bets.LookupBets(self._game.name, resolver=self._core.nick)
   coins, item = self._game.ComputeCurrentJackpot(pool)
   warning_str += 'Current jackpot is %s and a(n) %s' % (
       util_lib.FormatHypecoins(coins), item.human_name)
   self._Reply(self._core.default_channel, warning_str)
Exemple #20
0
    def _Handle(
            self, channel: channel_pb2.Channel, user: user_pb2.User,
            target_user: Optional[user_pb2.User]
    ) -> hype_types.CommandResponse:
        if target_user:
            balance = self._core.bank.GetBalance(target_user)
            for game in self._core.betting_games:
                game_bets = self._core.bets.LookupBets(game.name, target_user)
                for bet in game_bets.get(target_user.user_id, []):
                    balance += bet.amount
            return ('%s has a net worth of %s' %
                    (target_user.display_name,
                     util_lib.FormatHypecoins(balance, abbreviate=True)))

        # Top 4 plebs by net worth.
        pleb_balances = defaultdict(int)  # user_id -> worth
        pleb_balances.update(self._core.bank.GetUserBalances(plebs_only=True))
        for game in self._core.betting_games:
            game_bets = self._core.bets.LookupBets(game.name)
            for pleb, pleb_bets in game_bets.items():
                for bet in pleb_bets:
                    pleb_balances[pleb] += bet.amount
        pleb_balances = sorted([(pleb, balance)
                                for pleb, balance in pleb_balances.items()],
                               key=lambda x: x[1],
                               reverse=True)

        responses = ['Forbes 4:']
        position = 1
        prev_balance = -1
        for i, (user_id, balance) in enumerate(pleb_balances[:4]):
            user = self._core.interface.FindUser(user_id)
            if balance != prev_balance:
                position = i + 1
                prev_balance = balance
            responses.append('#{}: {:>6} - {}'.format(
                position, util_lib.FormatHypecoins(balance, abbreviate=True),
                user.display_name if user else user_id))
        return responses
Exemple #21
0
 def _LotteryWarningCallback(self, remaining=None):
     logging.info('Running lottery warning callback.')
     warning_str = ''
     if remaining is not None:
         warning_str += 'The lottery winner will be drawn in %s! ' % (
             util_lib.TimeDeltaToHumanDuration(remaining))
     pool = self._core.bets.LookupBets(self._game.name,
                                       resolver=self._core.name.lower())
     coins, item = self._game.ComputeCurrentJackpot(pool)
     item_str = inflect_lib.AddIndefiniteArticle(item.human_name)
     warning_str += 'Current jackpot is %s and %s' % (
         util_lib.FormatHypecoins(coins), item_str)
     self._core.PublishMessage('lottery', warning_str)
Exemple #22
0
  def MintNewHypeCoins(self):
    """Creates new HypeCoins if MINT_ACCOUNT is running low.

    Specifically, if the MINT_ACCOUNT has less than 25% of the total HypeCoin
    market size, this method will mint new coins scaling linearly with the
    number of users, and logarithmically with the total market size.
    """
    mint_balance = self.GetBalance(MINT_ACCOUNT)
    num_users, coins_in_circulation = self.GetBankStats()
    if mint_balance >= coins_in_circulation // 4:
      logging.info(
          'Mint balance (%s) >= 25%% of market (%s), not minting new coins',
          util_lib.FormatHypecoins(mint_balance),
          util_lib.FormatHypecoins(coins_in_circulation))
      return

    num_coins_to_mint = max(
        5000, int(math.log(coins_in_circulation, 2) * num_users * 1000))
    logging.info('Minting %s', util_lib.FormatHypecoins(num_coins_to_mint))
    if not self._Deposit(MINT_ACCOUNT, num_coins_to_mint, 'Minting', None):
      logging.error('Minting %s failed',
                    util_lib.FormatHypecoins(num_coins_to_mint))
Exemple #23
0
 def _HandleList(
         self, unused_channel: channel_pb2.Channel,
         unused_user: user_pb2.User,
         all_greetings: List[Tuple[int,
                                   Text]]) -> hype_types.CommandResponse:
     msgs = [
         'You can purchase one of the following upgraded greetings from '
         '%s' % self._core.name
     ]
     for i, greeting in enumerate(all_greetings):
         msgs.append('  %sgreet %d [%s] - \'%s\'' %
                     (self.command_prefix, i,
                      util_lib.FormatHypecoins(greeting[0]), greeting[1]))
     return msgs
Exemple #24
0
    def _BuildGreeting(self, user, time_of_day=None):
        """Builds a reply to user when they need to be greeted."""
        hour = arrow.now(self._core.timezone).hour

        if 3 <= hour < 12:
            true_time_of_day = 'Morning'
        elif 12 <= hour < 18:
            true_time_of_day = 'Afternoon'
        else:
            true_time_of_day = 'Evening'

        if not time_of_day:
            time_of_day = true_time_of_day
        time_of_day = time_of_day.title()

        # We build ranges of hours that correspond to the time of day given (e.g.
        # morning), and the 3 hours surrounding that range. We then compare that to
        # what time the user said it was, and adjust our level of snark
        # commensurately.
        time_ranges = (range(3, 12), list(range(0, 3)) + list(range(12, 15)))
        if time_of_day == 'Afternoon':
            time_ranges = (range(12,
                                 18), list(range(9, 12)) + list(range(18, 21)))
        elif time_of_day == 'Evening':
            time_ranges = (list(range(0, 3)) + list(range(18, 24)),
                           list(range(15, 18)) + list(range(3, 6)))

        greeting_params = {
            'user': user.display_name,
            'time_of_day': time_of_day
        }
        custom_greeting = self._core.store.GetValue(user.user_id, 'greetings')
        if hour in time_ranges[0]:
            greeting = custom_greeting or '{time_of_day}, {user}'
        elif hour in time_ranges[1]:
            greeting = '"{time_of_day}", {user}'
        else:
            greeting = 'Not even close {user}'

        if '{bal}' in greeting:
            greeting_params['bal'] = util_lib.FormatHypecoins(
                self._core.bank.GetBalance(user))
        try:
            return greeting.format(**greeting_params)
        except Exception as e:
            logging.info('GreetingCommand exception: %s', e)
            self._core.bank.FineUser(user, 100, 'Bad greeting', self._Reply)
            return ('%s has an invalid greeting and feels bad for trying to '
                    'break %s' % (user, self._core.name))
Exemple #25
0
 def _Handle(self, channel, user, account):
   if account or coin_lib.IsSubAccount(user):
     return 'You cannot reset sub-accounts.'
   cur_balance = self._core.bank.GetBalance(user)
   if cur_balance > 5000:
     return ('Surprisingly, I don\'t like to steal hypecoins. '
             'Your balance remains %s') % util_lib.FormatHypecoins(cur_balance)
   if cur_balance <= 0:
     self._Reply(
         channel,
         '%s has been foolish and unwise with their HypeCoins.' % user)
   bailout_amount = 5000 - cur_balance
   if not self._core.bank.ProcessPayment(
       coin_lib.MINT_ACCOUNT, user, bailout_amount, 'Bailout', self._Reply):
     return messages.HYPECOIN_MINT_EXHAUSTION_STR
Exemple #26
0
 def _Handle(self, channel: channel_pb2.Channel,
             user: user_pb2.User) -> hype_types.CommandResponse:
     pool = self._core.bets.LookupBets(self._game.name,
                                       resolver=self._core.name.lower())
     jackpot, item = self._game.ComputeCurrentJackpot(pool)
     item_str = inflect_lib.AddIndefiniteArticle(item.human_name)
     responses = [
         'Current jackpot is %s and %s' %
         (util_lib.FormatHypecoins(jackpot), item_str)
     ]
     for user_bets in pool.values():
         for bet in user_bets:
             responses.append(
                 '- %s, %s' %
                 (bet.user.display_name, self._game.FormatBet(bet)))
     return responses
Exemple #27
0
  def _Withdraw(self, user, num_coins, tx_details, msg_fn, can_overdraft=False):
    """Subtracts num_coins from user's balance.

    Args:
      user: {string} name of account from which to withdraw.
      num_coins: {int} number of hype coins to withdraw.
      tx_details: {dict} details of transaction.
      msg_fn: {callable(channel, msg)} function to send messages.
      can_overdraft: {boolean} whether it is possible to overdraft the account.
        If True, the account balance can go negative and no fees will be
        charged. If False, the transaction will fail and an overdraft fee will
        be assessed if there are insufficient funds for the transaction.

    Returns:
      {boolean} whether withdrawal was successful.
    """
    if num_coins < 0:
      logging.error('Withdraw called with negative value: %s, %s', user,
                    num_coins)
      return False
    # TODO(someone): This should really be a transaction.
    with self._withdraw_lock:
      balance = self.GetBalance(user)
      if balance < num_coins and not can_overdraft:
        logging.info('Overdraft: %s, %d > %d', user, num_coins, balance)
        overdraft_fee = max(self._MIN_OVERDRAFT_FEE,
                            int(balance * self._MAX_OVERDRAFT_FEE_PERCENT))
        self.ProcessPayment(
            user, FEE_ACCOUNT, overdraft_fee, 'Overdraft fee', msg_fn,
            can_overdraft=True)
        return False

      tx_details['type'] = 'withdrawal'
      tx_name = 'DEBIT %s %s' % (num_coins, user)
      self._store.RunInTransaction(
          self._BankTransaction,
          user, (-1 * num_coins),
          tx_details,
          tx_name=tx_name)
      if msg_fn:
        msg_fn(user, '%s withdrawn from your account. (%s)' %
               (util_lib.FormatHypecoins(num_coins),
                tx_details.get('details', '')))
    # TODO(someone): Maybe fix returns now that RunInTransaction can throw.
    return True
Exemple #28
0
 def _Handle(self, channel: Channel, user: str,
             stack_amount: str) -> hypecore.MessageType:
     num_stacks = util_lib.SafeCast(stack_amount, int, 0)
     if not num_stacks:
         self._core.bets.FineUser(user, 1,
                                  'You must buy at least one HypeStack.',
                                  self._Reply)
         return
     hypecoin_amount = self._core.hypestacks.PriceForHypeStacks(
         user, num_stacks)
     if not hypecoin_amount:
         return
     summary = 'purchase of %s for %s' % (inflect_lib.Plural(
         num_stacks,
         'HypeStack'), util_lib.FormatHypecoins(hypecoin_amount))
     purchase_details = {
         'num_stacks': num_stacks,
         'summary': summary,
         'cost': hypecoin_amount
     }
     self._core.request_tracker.RequestConfirmation(
         user, summary, purchase_details,
         self._core.hypestacks.PurchaseStacks)
Exemple #29
0
 def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User,
             target_user: user_pb2.User) -> hype_types.CommandResponse:
     balance = self._core.bank.GetBalance(target_user)
     return '%s has %s' % (target_user.display_name,
                           util_lib.FormatHypecoins(balance))
Exemple #30
0
    def _Handle(self, channel: channel_pb2.Channel, user: user_pb2.User,
                me: Text, users_or_games: Text) -> hype_types.CommandResponse:
        game_names = {g.name.lower(): g for g in self._core.betting_games}
        desired_games = set()
        users = {}
        if me:
            users[user.user_id] = user
        for user_or_game in (users_or_games or '').split():
            if user_or_game in game_names:
                desired_games.add(game_names[user_or_game])
            elif user_or_game == 'me':
                users[user.user_id] = user
            else:
                maybe_user = self._core.interface.FindUser(user_or_game)
                if maybe_user:
                    users[maybe_user.user_id] = maybe_user
        query_name = '%s%s%s' % (', '.join(
            [u.display_name
             for u in users.values()]), ' - ' if users and desired_games else
                                 '', ', '.join([g.name
                                                for g in desired_games]))

        # Default behaviors if not specified.
        if not users:
            users = {None: None}  # This will allow all users in a LookupBets.
        if not desired_games:
            desired_games = self._core.betting_games

        bets = []
        bet_total = 0
        for game in desired_games:
            for bet_user in users.values():
                bets_by_user = self._core.bets.LookupBets(game.name, bet_user)
                for _, user_bets in bets_by_user.items():
                    for bet in user_bets:
                        if len(users) > 1 or users == {None: None}:
                            bets.append(
                                (bet.amount, '- %s, %s' %
                                 (bet.user.display_name, game.FormatBet(bet))))
                        else:
                            bets.append(
                                (bet.amount, '- %s' % game.FormatBet(bet)))
                        bet_total += bet.amount
        bets.sort(key=lambda bet: bet[0], reverse=True)
        bets = [betstring for _, betstring in bets]

        if not bets:
            query_str = '%s has n' % query_name if query_name else 'N'
            return '%so current bets. Risk aversion is unbecoming' % query_str

        responses = [
            '%s current bets [%s, %s]' %
            (query_name or 'All', inflect_lib.Plural(
                len(bets), 'bet'), util_lib.FormatHypecoins(bet_total))
        ]
        if (len(bets) > self._params.num_bets
                and channel.visibility == channel_pb2.Channel.PUBLIC):
            responses.append('Only showing %d bets, addiction is no joke.' %
                             self._params.num_bets)
            bets = bets[:self._params.num_bets]

        responses.extend(bets)
        return responses