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))
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 ([], {})
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)
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
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')))
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.'
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
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
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
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?'
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
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
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))
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
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
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
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
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))
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)
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
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)
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))
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
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))
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
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
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
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)
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))
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