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
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)
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)
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)
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)
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' }
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)
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])))
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])))
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"))
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"))
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
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
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
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)
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)