Esempio n. 1
0
def collect_policy_rate_and_value(alice: Alice, rate: int, value: int,
                                  shares: int, force: bool) -> Tuple[int, int]:

    policy_value_provided = bool(value) or bool(rate)
    if not policy_value_provided:

        # TODO #1709 - Fine tuning and selection of default rates
        rate = alice.default_rate  # wei

        if not force:
            default_gwei = Web3.fromWei(rate, 'gwei')  # wei -> gwei
            prompt = "Confirm rate of {node_rate} gwei * {shares} nodes ({period_rate} gwei per period)?"

            if not click.confirm(prompt.format(
                    node_rate=default_gwei,
                    period_rate=default_gwei * shares,
                    shares=shares),
                                 default=True):
                interactive_rate = click.prompt(
                    'Enter rate per period in gwei', type=GWEI)
                # TODO: Interactive rate sampling & validation (#1709)
                interactive_prompt = prompt.format(
                    node_rate=interactive_rate,
                    period_rate=interactive_rate * shares,
                    shares=shares)
                click.confirm(interactive_prompt, default=True, abort=True)
                rate = Web3.toWei(interactive_rate, 'gwei')  # gwei -> wei

    return rate, value
Esempio n. 2
0
def paint_preallocation_status(emitter, preallocation_agent,
                               token_agent) -> None:
    blockchain = token_agent.blockchain

    staking_address = preallocation_agent.principal_contract.address

    token_balance = NU.from_nunits(token_agent.get_balance(staking_address))
    eth_balance = Web3.fromWei(blockchain.client.get_balance(staking_address),
                               'ether')
    initial_locked_amount = NU.from_nunits(
        preallocation_agent.initial_locked_amount)
    current_locked_amount = NU.from_nunits(preallocation_agent.unvested_tokens)
    available_amount = NU.from_nunits(preallocation_agent.available_balance)
    end_timestamp = preallocation_agent.end_timestamp

    width = 64
    output = f"""
{" Addresses ".center(width, "-")}
Staking contract: ... {staking_address}
Beneficiary: ........ {preallocation_agent.beneficiary}

{" Locked Tokens ".center(width, "-")}
Initial locked amount: {initial_locked_amount}
Current locked amount: {current_locked_amount}
Locked until: ........ {maya.MayaDT(epoch=end_timestamp)}

{" NU and ETH Balance ".center(width, "-")}
NU balance: .......... {token_balance}
    Available: ....... {available_amount}
ETH balance: ......... {eth_balance} ETH
"""
    emitter.echo(output)
Esempio n. 3
0
    def retrieve(self, request, *args, **kwargs):
        game = self.get_object()

        prize_data = []

        if game.status in (Game.STATUS_PUBLISHED, Game.STATUS_FINISHING):
            i = 1
            for prize in game.calculate_prizes():
                prize_data.append({
                    'address': '0x0000000000000000000000000000000000000000',
                    'position': i,
                    'prize_amount': Web3.fromWei(prize, 'ether')
                })

                i += 1

        elif game.status == Game.STATUS_FINISHED:
            i = 1

            for address, prize in game.get_winners().items():
                prize_data.append({
                    'address': address,
                    'position': i,
                    'prize_amount': prize
                })

                i += 1

        serializer = GameWinner(prize_data, many=True)

        return Response(serializer.data)
Esempio n. 4
0
def from_wei(amount_in_wei: int, decimals: int = DECIMALS_18) -> Decimal:
    """Convert token amount from wei to ether, quantized to the specified number of decimal places."""
    # Coerce to Decimal because Web3.fromWei can return int 0
    amount_in_ether = Decimal(Web3.fromWei(amount_in_wei, "ether"))
    decimal_places = Decimal(10)**-abs(decimals)
    return amount_in_ether.quantize(decimal_places,
                                    context=ETHEREUM_DECIMAL_CONTEXT)
Esempio n. 5
0
def confirm_staged_grant(emitter, grant_request: Dict, federated: bool, seconds_per_period=None) -> None:

    pretty_request = grant_request.copy()  # WARNING: Do not mutate

    if federated:  # Boring
        table = [[field.capitalize(), value] for field, value in pretty_request.items()]
        emitter.echo(tabulate(table, tablefmt="simple"))
        return

    period_rate = Web3.fromWei(pretty_request['n'] * pretty_request['rate'], 'gwei')
    pretty_request['rate'] = f"{pretty_request['rate']} wei/period * {pretty_request['n']} nodes"

    expiration = pretty_request['expiration']
    periods = calculate_period_duration(future_time=MayaDT.from_datetime(expiration),
                                        seconds_per_period=seconds_per_period)
    periods += 1  # current period is always included
    pretty_request['expiration'] = f"{pretty_request['expiration']} ({periods} periods)"

    # M of N
    pretty_request['Threshold Shares'] = f"{pretty_request['m']} of {pretty_request['n']}"
    del pretty_request['m']
    del pretty_request['n']

    def prettify_field(field):
        field_words = [word.capitalize() for word in field.split('_')]
        field = ' '.join(field_words)
        return field

    table = [[prettify_field(field), value] for field, value in pretty_request.items()]
    table.append(['Period Rate', f'{period_rate} gwei'])
    table.append(['Policy Value', f'{period_rate * periods} gwei'])

    emitter.echo("\nSuccessfully staged grant, Please review the details:\n", color='green')
    emitter.echo(tabulate(table, tablefmt="simple"))
    click.confirm('\nGrant access and sign transaction?', abort=True)
Esempio n. 6
0
    def get_prize_amount(self, obj):
        result = 0

        try:
            stat = self.__get_stat__(obj)
            result = Web3.fromWei(stat.get('prizeAmount'), 'ether')
        except:
            result = float(getattr(obj, 'prize_amount'))

        return {
            'amount': float(result),
            'currency': 'UNIT' if obj.type == Game.TOKEN_GAME else 'ETH'
        }
Esempio n. 7
0
    def get_prize_amount(self, obj):
        stat = self.__get_stat__(obj)
        result = 0

        try:
            result = stat.get('prizeAmount')
        except:
            pass

        if result is not None and result > 0:
            result = Web3.fromWei(result, 'ether')
        else:
            result = float(getattr(obj, 'prize_amount'))

        return float(result)
Esempio n. 8
0
    def get_winners(self):
        """
        :rtype: dict
        """
        if self.smart_contract_id in (None, '0'):
            raise AttributeError('Smart contract id can not be empty')

        contract = self.get_smart_contract()
        winners, prizes = contract.call().getWinners()
        result = {}

        #Setting address
        for i, winner in enumerate([w_player.lower() for w_player in winners]):
            result[winner] = Web3.fromWei(prizes[i], 'ether')

        return OrderedDict(reversed(sorted(result.items(),
                                           key=lambda t: t[1])))
Esempio n. 9
0
    def get_winners(self):
        """
        :rtype: dict
        """
        if not Web3.isAddress(self.smart_contract_id):
            return []

        contract = self.get_smart_contract()
        winners, prizes = contract.call().getWinners()
        result = {}

        #Setting address
        for i, winner in enumerate([w_player for w_player in winners]):
            result[winner] = Web3.fromWei(prizes[i], 'ether')

        return OrderedDict(reversed(sorted(result.items(),
                                           key=lambda t: t[1])))
Esempio n. 10
0
def paint_staking_accounts(emitter, signer, registry, domain):
    from nucypher.blockchain.eth.actors import Staker

    rows = list()
    blockchain = BlockchainInterfaceFactory.get_interface()
    token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=registry)
    for account in signer.accounts:
        eth = str(Web3.fromWei(blockchain.client.get_balance(account), 'ether')) + " ETH"
        nu = str(NU.from_nunits(token_agent.get_balance(account)))

        staker = Staker(checksum_address=account,
                        domain=domain,
                        registry=registry)
        staker.refresh_stakes()
        is_staking = 'Yes' if bool(staker.stakes) else 'No'
        rows.append((is_staking, account, eth, nu))
    headers = ('Staking', 'Account', 'ETH', 'NU')
    emitter.echo(tabulate.tabulate(rows, showindex=True, headers=headers, tablefmt="fancy_grid"))
Esempio n. 11
0
def paint_staking_accounts(emitter, wallet, registry):
    from nucypher.blockchain.eth.actors import Staker

    rows = list()
    for account in wallet.accounts:
        eth = str(Web3.fromWei(wallet.eth_balance(account), 'ether')) + " ETH"
        nu = str(NU.from_nunits(wallet.token_balance(account, registry)))

        staker = Staker(is_me=True,
                        checksum_address=account,
                        registry=registry)
        staker.refresh_stakes()
        is_staking = 'Yes' if bool(staker.stakes) else 'No'
        rows.append((is_staking, account, eth, nu))
    headers = ('Staking', 'Account', 'ETH', 'NU')
    emitter.echo(
        tabulate.tabulate(rows,
                          showindex=True,
                          headers=headers,
                          tablefmt="fancy_grid"))
Esempio n. 12
0
def select_client_account(emitter,
                          provider_uri: str = None,
                          signer: Signer = None,
                          signer_uri: str = None,
                          wallet: Wallet = None,
                          prompt: str = None,
                          default: int = 0,
                          registry=None,
                          show_eth_balance: bool = False,
                          show_nu_balance: bool = False,
                          show_staking: bool = False,
                          network: str = None,
                          poa: bool = None) -> str:
    """
    Interactively select an ethereum wallet account from a table of nucypher account metadata.

    Note: Showing ETH and/or NU balances, causes an eager blockchain connection.
    """

    if wallet and (provider_uri or signer_uri or signer):
        raise ValueError(
            "If a wallet is provided, don't provide a signer, provider URI, or signer URI."
        )

    # We use Wallet internally as an account management abstraction
    if not wallet:

        if signer and signer_uri:
            raise ValueError('Pass either signer or signer_uri but not both.')

        if not provider_uri and not signer_uri:
            raise ValueError(
                "At least a provider URI or signer URI is necessary to select an account"
            )

        if provider_uri:
            # Lazy connect the blockchain interface
            if not BlockchainInterfaceFactory.is_interface_initialized(
                    provider_uri=provider_uri):
                BlockchainInterfaceFactory.initialize_interface(
                    provider_uri=provider_uri, poa=poa, emitter=emitter)

        if signer_uri:
            testnet = network != NetworksInventory.MAINNET
            signer = Signer.from_signer_uri(signer_uri, testnet=testnet)

        wallet = Wallet(provider_uri=provider_uri, signer=signer)

    # Display accounts info
    if show_nu_balance or show_staking:  # Lazy registry fetching
        if not registry:
            if not network:
                raise ValueError("Pass network name or registry; Got neither.")
            registry = InMemoryContractRegistry.from_latest_publication(
                network=network)

    wallet_accounts = wallet.accounts
    enumerated_accounts = dict(enumerate(wallet_accounts))
    if len(enumerated_accounts) < 1:
        emitter.echo(NO_ETH_ACCOUNTS, color='red', bold=True)
        raise click.Abort()

    # Display account info
    headers = ['Account']
    if show_staking:
        headers.append('Staking')
    if show_eth_balance:
        headers.append('ETH')
    if show_nu_balance:
        headers.append('NU')

    rows = list()
    for index, account in enumerated_accounts.items():
        row = [account]
        if show_staking:
            staker = Staker(is_me=True,
                            checksum_address=account,
                            registry=registry)
            staker.refresh_stakes()
            is_staking = 'Yes' if bool(staker.stakes) else 'No'
            row.append(is_staking)
        if show_eth_balance:
            ether_balance = Web3.fromWei(wallet.eth_balance(account), 'ether')
            row.append(f'{ether_balance} ETH')
        if show_nu_balance:
            token_balance = NU.from_nunits(
                wallet.token_balance(account, registry))
            row.append(token_balance)
        rows.append(row)
    emitter.echo(tabulate(rows, headers=headers, showindex='always'))

    # Prompt the user for selection, and return
    prompt = prompt or GENERIC_SELECT_ACCOUNT
    account_range = click.IntRange(min=0, max=len(enumerated_accounts) - 1)
    choice = click.prompt(prompt, type=account_range, default=default)
    chosen_account = enumerated_accounts[choice]

    emitter.echo(SELECTED_ACCOUNT.format(choice=choice,
                                         chosen_account=chosen_account),
                 color='blue')
    return chosen_account
Esempio n. 13
0
    def handle(self, *args, **options):
        try:
            games = Game.objects.filter(status=Game.STATUS_PUBLISHED,
                                        type__in=(
                                            Game.TYPE_1_DAY,
                                            Game.TYPE_7_DAYS,
                                        ),
                                        started_at__lte=timezone.now(),
                                        ending_at__gt=timezone.now()).all()

            for game in games:

                if not Web3.isAddress(game.smart_contract_id):
                    continue

                logger.info('Processing game %d' % (game.id))

                keep_trying = True

                stat = {}
                players = []

                while keep_trying:
                    try:
                        stat = game.get_stat()
                        players = game.get_players()

                        keep_trying = False

                        logger.info('Game %d: Pulling game stats.' % (game.id))
                        logger.debug('Game %d: Stat: %s' %
                                     (game.id, str(stat)))
                    except socket.timeout:
                        logger.error(
                            'Game %d: Handled timeout error. Trying again.')
                        keep_trying = True

                stat_num_players = stat.get('numPlayers', 0)

                GamePlayer.objects.filter(game_id=game.id).delete()

                for player in players:
                    GamePlayer.objects.create(game_id=game.id, wallet=player)

                logger.info('Game %d: Checking num players')
                logger.debug(
                    'Game %d: Game num players: %d Stat num players: %d' %
                    (game.id, game.num_players, stat_num_players))

                if game.num_players < stat_num_players:
                    logger.info('Game %d: Updating game' % (game.id))
                    game.num_players = stat_num_players
                    game.prize_amount = Web3.fromWei(
                        stat.get('prizeAmount', 0), 'ether')
                    game.save()

                    logger.info('Game %d: Sending notification to debices' %
                                (game.id))
                    push_message = push.GameNewPlayerPushMessage(payload=game)
                    PushHelper.inform_all_devices(push_message)

        except Game.DoesNotExist:
            message = 'No games to proceed'
            logger.error(message)
            print(message)

        try:
            games = Game.objects.filter(status=Game.STATUS_PUBLISHED,
                                        type__in=(
                                            Game.TYPE_30_DAYS,
                                            Game.TOKEN_GAME,
                                        ),
                                        started_at__lte=timezone.now(),
                                        ending_at__gt=timezone.now()).all()

            for game in games:
                child_games = Game.objects\
                    .exclude(type__in=(Game.TYPE_30_DAYS, Game.TOKEN_GAME,))\
                    .exclude(status__in=(Game.STATUS_CANCELED,))\
                    .filter(started_at__gte=game.started_at, ending_at__lte=game.ending_at)

                if game.type != Game.TOKEN_GAME:
                    game.prize_amount = 0

                num_players_qs = GamePlayer.objects \
                    .distinct('wallet') \
                    .exclude(game__type__in=(Game.TYPE_30_DAYS, Game.TOKEN_GAME,)) \
                    .exclude(game__status=Game.STATUS_CANCELED) \
                    .filter(game__started_at__gte=game.started_at, game__ending_at__lte=game.ending_at)

                if game.type == Game.TYPE_30_DAYS:
                    num_players_qs = num_players_qs.filter(is_winner=False)\
                                                .filter(game__status=Game.STATUS_FINISHED)

                game.num_players = num_players_qs.count()

                GamePlayer.objects.filter(game_id=game.id).delete()

                for player in num_players_qs:
                    GamePlayer.objects.create(game_id=game.id,
                                              wallet=player.wallet,
                                              is_winner=False,
                                              prize_amount=0)

                for child_game in child_games:
                    if game.type != Game.TOKEN_GAME:
                        game.prize_amount += ((child_game.prize_amount / 0.8) *
                                              0.1)

                game.save()

        except Game.DoesNotExist:
            pass
Esempio n. 14
0
def select_client_account(emitter,
                          eth_provider_uri: str = None,
                          signer: Signer = None,
                          signer_uri: str = None,
                          prompt: str = None,
                          default: int = 0,
                          registry: BaseContractRegistry = None,
                          show_eth_balance: bool = False,
                          show_nu_balance: bool = False,
                          show_staking: bool = False,
                          network: str = None,
                          poa: bool = None) -> str:
    """
    Interactively select an ethereum wallet account from a table of nucypher account metadata.

    Note: Showing ETH and/or NU balances, causes an eager blockchain connection.
    """

    if signer and signer_uri:
        raise ValueError('Pass either signer or signer_uri but not both.')

    if not any((eth_provider_uri, signer_uri, signer)):
        raise ValueError(
            "At least a provider URI, signer URI or signer must be provided to select an account"
        )

    if eth_provider_uri:
        # Connect to the blockchain in order to select an account
        if not BlockchainInterfaceFactory.is_interface_initialized(
                eth_provider_uri=eth_provider_uri):
            BlockchainInterfaceFactory.initialize_interface(
                eth_provider_uri=eth_provider_uri, poa=poa, emitter=emitter)
        if not signer_uri:
            signer_uri = eth_provider_uri

    blockchain = BlockchainInterfaceFactory.get_interface(
        eth_provider_uri=eth_provider_uri)

    if signer_uri and not signer:
        testnet = network != NetworksInventory.MAINNET
        signer = Signer.from_signer_uri(signer_uri, testnet=testnet)

    # Display accounts info
    if show_nu_balance or show_staking:  # Lazy registry fetching
        if not registry:
            if not network:
                raise ValueError("Pass network name or registry; Got neither.")
            registry = InMemoryContractRegistry.from_latest_publication(
                network=network)

    enumerated_accounts = dict(enumerate(signer.accounts))
    if len(enumerated_accounts) < 1:
        emitter.echo(NO_ETH_ACCOUNTS, color='red', bold=True)
        raise click.Abort()
    elif len(enumerated_accounts) == 1:
        # There are no choices if there is only one available address.
        return enumerated_accounts[0]

    # Display account info
    headers = ['Account']
    if show_staking:
        headers.append('Staking')
    if show_eth_balance:
        headers.append('ETH')
    if show_nu_balance:
        headers.append('NU')

    rows = list()
    for index, account in enumerated_accounts.items():
        row = [account]
        if show_staking:
            staker = Staker(domain=network,
                            checksum_address=account,
                            registry=registry)
            staker.refresh_stakes()
            is_staking = 'Yes' if bool(staker.stakes) else 'No'
            row.append(is_staking)
        if show_eth_balance:
            ether_balance = Web3.fromWei(
                blockchain.client.get_balance(account), 'ether')
            row.append(f'{ether_balance} ETH')
        if show_nu_balance:
            token_agent = ContractAgency.get_agent(NucypherTokenAgent,
                                                   registry=registry)
            token_balance = NU.from_units(
                token_agent.get_balance(account, registry))
            row.append(token_balance)
        rows.append(row)
    emitter.echo(tabulate(rows, headers=headers, showindex='always'))

    # Prompt the user for selection, and return
    prompt = prompt or GENERIC_SELECT_ACCOUNT
    account_range = click.IntRange(min=0, max=len(enumerated_accounts) - 1)
    choice = click.prompt(prompt, type=account_range, default=default)
    chosen_account = enumerated_accounts[choice]

    emitter.echo(SELECTED_ACCOUNT.format(choice=choice,
                                         chosen_account=chosen_account),
                 color='blue')
    return chosen_account
Esempio n. 15
0
def grant(general_config,
          bob,
          bob_encrypting_key,
          bob_verifying_key,
          label,
          value,
          rate,
          expiration,
          m, n,
          character_options,
          config_file,
          force):
    """Create and enact an access policy for some Bob. """

    # Setup
    emitter = setup_emitter(general_config)
    ALICE = character_options.create_character(emitter, config_file, general_config.json_ipc)

    # Policy option validation
    if ALICE.federated_only:
        if any((value, rate)):
            message = "Can't use --value or --rate with a federated Alice."
            raise click.BadOptionUsage(option_name="--value, --rate", message=message)
    elif bool(value) and bool(rate):
        raise click.BadOptionUsage(option_name="--rate", message="Can't use --value if using --rate")

    # Grantee selection
    if bob and any((bob_encrypting_key, bob_verifying_key)):
        message = '--bob cannot be used with --bob-encrypting-key or --bob-veryfying key'
        raise click.BadOptionUsage(option_name='--bob', message=message)

    if bob:
        card = Card.load(identifier=bob)
        if card.character is not Bob:
            emitter.error('Grantee card is not a Bob.')
            raise click.Abort
        paint_single_card(emitter=emitter, card=card)
        if not force:
            click.confirm('Is this the correct grantee (Bob)?', abort=True)
        bob_encrypting_key = card.encrypting_key.hex()
        bob_verifying_key = card.verifying_key.hex()

    # Interactive collection follows:
    # TODO: Extricate to support modules
    # - Disclaimer
    # - Label
    # - Expiration Date & Time
    # - M of N
    # - Policy Value (ETH)

    # Policy Expiration
    # TODO: Remove this line when the time is right.
    paint_probationary_period_disclaimer(emitter)

    # Label
    if not label:
        label = click.prompt(f'Enter label to grant Bob {bob_verifying_key[:8]}', type=click.STRING)

    if not force and not expiration:
        if ALICE.duration_periods:
            # TODO: use a default in days or periods?
            expiration = maya.now() + timedelta(days=ALICE.duration_periods)  # default
            if not click.confirm(f'Use default policy duration (expires {expiration})?'):
                expiration = click.prompt('Enter policy expiration datetime', type=click.DateTime())
        else:
            # No policy duration default default available; Go interactive
            expiration = click.prompt('Enter policy expiration datetime', type=click.DateTime())

    # TODO: Remove this line when the time is right.
    enforce_probationary_period(emitter=emitter, expiration=expiration)

    # Policy Threshold and Shares
    if not n:
        n = ALICE.n
        if not force and not click.confirm(f'Use default value for N ({n})?', default=True):
            n = click.prompt('Enter total number of shares (N)', type=click.INT)
    if not m:
        m = ALICE.m
        if not force and not click.confirm(f'Use default value for M ({m})?', default=True):
            m = click.prompt('Enter threshold (M)', type=click.IntRange(1, n))

    # Policy Value
    policy_value_provided = bool(value) or bool(rate)
    if not ALICE.federated_only and not policy_value_provided:
        rate = ALICE.default_rate  # TODO #1709 - Fine tuning and selection of default rates
        if not force:
            default_gwei = Web3.fromWei(rate, 'gwei')
            prompt = "Confirm rate of {node_rate} gwei ({total_rate} gwei per period)?"
            if not click.confirm(prompt.format(node_rate=default_gwei, total_rate=default_gwei*n), default=True):
                interactive_rate = click.prompt('Enter rate per period in gwei', type=GWEI)
                # TODO: Validate interactively collected rate (#1709)
                click.confirm(prompt.format(node_rate=rate, total_rate=rate*n), default=True, abort=True)
                rate = Web3.toWei(interactive_rate, 'gwei')

    # Request
    grant_request = {
        'bob_encrypting_key': bob_encrypting_key,
        'bob_verifying_key': bob_verifying_key,
        'label': label,
        'm': m,
        'n': n,
        'expiration': expiration,
    }
    if not ALICE.federated_only:
        if value:
            grant_request['value'] = value
        elif rate:
            grant_request['rate'] = rate  # in wei

    if not force and not general_config.json_ipc:
        confirm_staged_grant(emitter=emitter, grant_request=grant_request)
    emitter.echo(f'Granting Access to {bob_verifying_key[:8]}', color='yellow')
    return ALICE.controller.grant(request=grant_request)
Esempio n. 16
0
    def handle(self, *args, **options):
        game_id = options.get('game_id', 0)

        try:
            if game_id > 0:
                games = Game.objects.filter(id=game_id)
            else:
                games = Game.objects\
                    .exclude(status__in=(Game.STATUS_PUBLISHED, Game.STATUS_FINISHING, Game.STATUS_CANCELED))\
                    .exclude(player__is_winner=True)\
                    .distinct()

            for game in games:

                if not Web3.isAddress(game.smart_contract_id):
                    logger.info('Game %d does not have valid address' %
                                (game.id))
                    continue

                logger.info('Processing game %d' % (game.id))

                keep_trying = True

                stat = {}
                players = []
                winners = {}

                while keep_trying:
                    try:
                        stat = game.get_stat()
                        players = game.get_players()
                        winners = game.get_winners()

                        keep_trying = False

                        logger.info('Game %d: Pulling game stats.' % (game.id))
                        logger.debug('Game %d: Stat: %s' %
                                     (game.id, str(stat)))
                    except socket.timeout:
                        logger.error(
                            'Game %d: Handled timeout error. Trying again.')
                        keep_trying = True

                stat_num_players = stat.get('numPlayers', 0)

                GamePlayer.objects.filter(game_id=game.id).delete()

                for player in players:
                    GamePlayer.objects.create(game_id=game.id,
                                              wallet=player,
                                              is_winner=(player
                                                         in winners.keys()),
                                              prize_amount=winners.get(
                                                  player, 0))

                logger.info('Game %d: Checking num players')
                logger.debug(
                    'Game %d: Game num players: %d Stat num players: %d' %
                    (game.id, game.num_players, stat_num_players))

                if game.num_players < stat_num_players:
                    logger.info('Game %d: Updating game' % (game.id))
                    game.num_players = stat_num_players
                    game.prize_amount = Web3.fromWei(
                        stat.get('prizeAmount', 0), 'ether')
                    game.save()

        except Game.DoesNotExist:
            message = 'No games to proceed'
            logger.error(message)
            print(message)