Ejemplo n.º 1
0
def download_registry(config_root, registry_outfile, network, force):
    """
    Download the latest registry.
    """
    # Init
    emitter = StdoutEmitter()
    _ensure_config_root(config_root)

    github_source = GithubRegistrySource(
        network=network, registry_name=BaseContractRegistry.REGISTRY_NAME)
    source_manager = RegistrySourceManager(sources=[github_source])

    if not force:
        prompt = f"Fetch and download latest contract registry from {github_source}?"
        click.confirm(prompt, abort=True)
    try:
        registry = InMemoryContractRegistry.from_latest_publication(
            source_manager=source_manager)
    except RegistrySourceManager.NoSourcesAvailable:
        emitter.message("Registry not available.", color="red")
        raise click.Abort

    try:
        output_filepath = registry.commit(filepath=registry_outfile,
                                          overwrite=force)
    except InMemoryContractRegistry.CantOverwriteRegistry:
        emitter.message(
            "Can't overwrite existing registry. Use '--force' to overwrite.",
            color="red")
        raise click.Abort
    emitter.message(
        f"Successfully downloaded latest registry to {output_filepath}")
Ejemplo n.º 2
0
def nucypher_cli(click_config, verbose, mock_networking, json_ipc, no_logs,
                 quiet, debug, no_registry, log_level):

    # Session Emitter for pre and post character control engagement.
    if json_ipc:
        emitter = JSONRPCStdoutEmitter(
            quiet=quiet, capture_stdout=NucypherClickConfig.capture_stdout)
    else:
        emitter = StdoutEmitter(
            quiet=quiet, capture_stdout=NucypherClickConfig.capture_stdout)

    click_config.attach_emitter(emitter)
    if not json_ipc:
        click_config.emit(message=NUCYPHER_BANNER)

    if log_level:
        GlobalConsoleLogger.set_log_level(log_level_name=log_level)
        globalLogPublisher.addObserver(SimpleObserver())

    if debug and quiet:
        raise click.BadOptionUsage(
            option_name="quiet",
            message="--debug and --quiet cannot be used at the same time.")

    if debug:
        click_config.log_to_sentry = False
        click_config.log_to_file = True  # File Logging
        globalLogPublisher.addObserver(SimpleObserver())  # Console Logging
        globalLogPublisher.removeObserver(logToSentry)  # No Sentry
        GlobalConsoleLogger.set_log_level(log_level_name='debug')

    elif quiet:  # Disable Logging
        globalLogPublisher.removeObserver(logToSentry)
        globalLogPublisher.removeObserver(SimpleObserver)
        globalLogPublisher.removeObserver(getJsonFileObserver())

    # Logging
    if not no_logs:
        GlobalConsoleLogger.start_if_not_started()

    # CLI Session Configuration
    click_config.verbose = verbose
    click_config.mock_networking = mock_networking
    click_config.json_ipc = json_ipc
    click_config.no_logs = no_logs
    click_config.quiet = quiet
    click_config.no_registry = no_registry
    click_config.debug = debug

    # Only used for testing outputs;
    # Redirects outputs to in-memory python containers.
    if mock_networking:
        click_config.emit(message="WARNING: Mock networking is enabled")
        click_config.middleware = MockRestMiddleware()
    else:
        click_config.middleware = RestMiddleware()

    # Global Warnings
    if click_config.verbose:
        click_config.emit(message="Verbose mode is enabled", color='blue')
Ejemplo n.º 3
0
def test_ursula_command_protocol_creation(ursula):

    emitter = StdoutEmitter()
    protocol = UrsulaCommandProtocol(ursula=ursula, emitter=emitter)

    assert protocol.ursula == ursula
    assert b'Ursula' in protocol.prompt
Ejemplo n.º 4
0
def rollback(  # Admin Actor Options
        provider_uri, contract_name, config_root, poa, force, etherscan,
        hw_wallet, deployer_address, registry_infile, registry_outfile, dev,
        se_test_mode):
    """
    Rollback a proxy contract's target.
    """
    # Init
    emitter = StdoutEmitter()
    _ensure_config_root(config_root)
    deployer_interface = _initialize_blockchain(poa, provider_uri)

    # Warnings
    _pre_launch_warnings(emitter, etherscan, hw_wallet)

    #
    # Make Authenticated Deployment Actor
    #
    ADMINISTRATOR, deployer_address, local_registry = _make_authenticated_deployment_actor(
        emitter, provider_uri, deployer_address, deployer_interface,
        contract_name, registry_infile, registry_outfile, hw_wallet, dev,
        force, se_test_mode)

    if not contract_name:
        raise click.BadArgumentUsage(
            message="--contract-name is required when using --rollback")
    existing_secret = click.prompt('Enter existing contract upgrade secret',
                                   hide_input=True)
    new_secret = click.prompt('Enter new contract upgrade secret',
                              hide_input=True,
                              confirmation_prompt=True)
    ADMINISTRATOR.rollback_contract(contract_name=contract_name,
                                    existing_plaintext_secret=existing_secret,
                                    new_plaintext_secret=new_secret)
Ejemplo n.º 5
0
def delete(force, card_id):
    """Delete an existing character card."""
    emitter = StdoutEmitter()
    card = select_card(emitter=emitter, card_identifier=card_id)
    if not force:
        click.confirm(f'Are you sure you want to delete {card}?', abort=True)
    card.delete()
    emitter.message(f'Deleted card for {card.id.hex()}.', color='red')
Ejemplo n.º 6
0
def transfer_ownership(  # Admin Actor Options
        provider_uri,
        contract_name,
        config_root,
        poa,
        force,
        etherscan,
        hw_wallet,
        deployer_address,
        registry_infile,
        registry_outfile,
        dev,
        se_test_mode,

        # Other
        target_address,
        gas):
    """
    Transfer ownership of contracts to another address.
    """
    # Init
    emitter = StdoutEmitter()
    _ensure_config_root(config_root)
    deployer_interface = _initialize_blockchain(poa, provider_uri)

    # Warnings
    _pre_launch_warnings(emitter, etherscan, hw_wallet)

    #
    # Make Authenticated Deployment Actor
    #
    ADMINISTRATOR, deployer_address, local_registry = _make_authenticated_deployment_actor(
        emitter, provider_uri, deployer_address, deployer_interface,
        contract_name, registry_infile, registry_outfile, hw_wallet, dev,
        force, se_test_mode)

    if not target_address:
        target_address = click.prompt("Enter new owner's checksum address",
                                      type=EIP55_CHECKSUM_ADDRESS)

    if contract_name:
        try:
            contract_deployer_class = ADMINISTRATOR.deployers[contract_name]
        except KeyError:
            message = f"No such contract {contract_name}. Available contracts are {ADMINISTRATOR.deployers.keys()}"
            emitter.echo(message, color='red', bold=True)
            raise click.Abort()
        else:
            contract_deployer = contract_deployer_class(
                registry=ADMINISTRATOR.registry,
                deployer_address=ADMINISTRATOR.deployer_address)
            receipt = contract_deployer.transfer_ownership(
                new_owner=target_address, transaction_gas_limit=gas)
            emitter.ipc(receipt, request_id=0, duration=0)  # TODO: #1216
    else:
        receipts = ADMINISTRATOR.relinquish_ownership(
            new_owner=target_address, transaction_gas_limit=gas)
        emitter.ipc(receipts, request_id=0, duration=0)  # TODO: #1216
Ejemplo n.º 7
0
def test_get_nucypher_password(mock_stdin, mock_account, confirm, capsys):
    mock_stdin.password(INSECURE_DEVELOPMENT_PASSWORD, confirm=confirm)
    result = get_nucypher_password(emitter=StdoutEmitter(), confirm=confirm)
    assert result == INSECURE_DEVELOPMENT_PASSWORD
    assert mock_stdin.empty()
    captured = capsys.readouterr()
    assert COLLECT_NUCYPHER_PASSWORD in captured.out
    if confirm:
        prompt = COLLECT_NUCYPHER_PASSWORD + f" ({NucypherKeyring.MINIMUM_PASSWORD_LENGTH} character minimum)"
        assert prompt in captured.out
Ejemplo n.º 8
0
def show(query, qrcode):
    """
    Lookup and view existing character card
    QUERY can be either the card id or nickname.
    """
    emitter = StdoutEmitter()
    try:
        card = select_card(emitter=emitter, card_identifier=query)
    except Card.UnknownCard as e:
        return emitter.error(str(e))
    paint_single_card(emitter=emitter, card=card, qrcode=qrcode)
Ejemplo n.º 9
0
def test_rapid_deployment(token_economics, test_registry):
    compiler = SolidityCompiler()
    allocation_registry = InMemoryAllocationRegistry()

    blockchain = _TesterBlockchain(eth_airdrop=False,
                                   test_accounts=4,
                                   compiler=compiler)

    # TODO: #1092 - TransactingPower
    blockchain.transacting_power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD,
                                                    account=blockchain.etherbase_account)
    blockchain.transacting_power.activate()
    deployer_address = blockchain.etherbase_account

    deployer = ContractAdministrator(deployer_address=deployer_address,
                                     registry=test_registry)

    secrets = dict()
    for deployer_class in deployer.upgradeable_deployer_classes:
        secrets[deployer_class.contract_name] = INSECURE_DEVELOPMENT_PASSWORD

    deployer.deploy_network_contracts(secrets=secrets, emitter=StdoutEmitter())

    all_yall = blockchain.unassigned_accounts

    # Start with some hard-coded cases...
    allocation_data = [{'beneficiary_address': all_yall[1],
                        'amount': token_economics.maximum_allowed_locked,
                        'duration_seconds': ONE_YEAR_IN_SECONDS},

                       {'beneficiary_address': all_yall[2],
                        'amount': token_economics.minimum_allowed_locked,
                        'duration_seconds': ONE_YEAR_IN_SECONDS*2},

                       {'beneficiary_address': all_yall[3],
                        'amount': token_economics.minimum_allowed_locked*100,
                        'duration_seconds': ONE_YEAR_IN_SECONDS*3}
                       ]

    # Pile on the rest
    for _ in range(NUMBER_OF_ALLOCATIONS_IN_TESTS - len(allocation_data)):
        random_password = ''.join(random.SystemRandom().choice(string.ascii_uppercase+string.digits) for _ in range(16))
        acct = w3.eth.account.create(random_password)
        beneficiary_address = acct.address
        amount = random.randint(token_economics.minimum_allowed_locked, token_economics.maximum_allowed_locked)
        duration = random.randint(token_economics.minimum_locked_periods*ONE_YEAR_IN_SECONDS,
                                  (token_economics.maximum_rewarded_periods*ONE_YEAR_IN_SECONDS)*3)
        random_allocation = {'beneficiary_address': beneficiary_address, 'amount': amount, 'duration_seconds': duration}
        allocation_data.append(random_allocation)

    deployer.deploy_beneficiary_contracts(allocations=allocation_data,
                                          allocation_registry=allocation_registry,
                                          interactive=False)
Ejemplo n.º 10
0
 def __cache_addresses(self) -> None:
     """
     Derives trezor ethereum addresses up to ADDRESS_CACHE_SIZE relative to
     the calculated base path and internally caches them for later use.
     """
     emitter = StdoutEmitter()
     for index in range(self.ADDRESS_CACHE_SIZE):
         hd_path = self.__get_address_path(index=index)
         address = self.__derive_account(hd_path=hd_path)
         self.__addresses[address] = hd_path
         message = f"Derived {address} ({self.derivation_root}/{index})"
         emitter.message(message)
Ejemplo n.º 11
0
def transfer_tokens(  # Admin Actor Options
        provider_uri,
        contract_name,
        config_root,
        poa,
        force,
        etherscan,
        hw_wallet,
        deployer_address,
        registry_infile,
        registry_outfile,
        dev,
        se_test_mode,

        # Other
        target_address,
        value):
    """
    Transfer tokens from contract's owner address to another address
    """
    # Init
    emitter = StdoutEmitter()
    _ensure_config_root(config_root)
    deployer_interface = _initialize_blockchain(poa, provider_uri)

    # Warnings
    _pre_launch_warnings(emitter, etherscan, hw_wallet)

    #
    # Make Authenticated Deployment Actor
    #
    ADMINISTRATOR, deployer_address, local_registry = _make_authenticated_deployment_actor(
        emitter, provider_uri, deployer_address, deployer_interface,
        contract_name, registry_infile, registry_outfile, hw_wallet, dev,
        force, se_test_mode)

    token_agent = ContractAgency.get_agent(NucypherTokenAgent,
                                           registry=local_registry)
    if not target_address:
        target_address = click.prompt("Enter recipient's checksum address",
                                      type=EIP55_CHECKSUM_ADDRESS)
    if not value:
        stake_value_range = click.FloatRange(min=0, clamp=False)
        value = NU.from_tokens(
            click.prompt(f"Enter value in NU", type=stake_value_range))

    click.confirm(
        f"Transfer {value} from {deployer_address} to {target_address}?",
        abort=True)
    receipt = token_agent.transfer(amount=value,
                                   sender_address=deployer_address,
                                   target_address=target_address)
    emitter.echo(f"OK | Receipt: {receipt['transactionHash'].hex()}")
Ejemplo n.º 12
0
def create(character_flag, verifying_key, encrypting_key, nickname, force):
    """Store a new character card"""
    emitter = StdoutEmitter()

    # Validate
    if not all((character_flag, verifying_key, encrypting_key)) and force:
        emitter.error(
            f'--verifying-key, --encrypting-key, and --type are required with --force enabled.'
        )

    # Card type
    from constant_sorrow.constants import ALICE, BOB
    flags = {'a': ALICE, 'b': BOB}
    if not character_flag:
        choice = click.prompt('Enter Card Type - (A)lice or (B)ob',
                              type=click.Choice(['a', 'b'],
                                                case_sensitive=False))
        character_flag = flags[choice]
    else:
        character_flag = flags[character_flag]

    # Verifying Key
    if not verifying_key:
        verifying_key = click.prompt('Enter Verifying Key',
                                     type=UMBRAL_PUBLIC_KEY_HEX)
    verifying_key = bytes.fromhex(verifying_key)  # TODO: Move / Validate

    # Encrypting Key
    if character_flag is BOB:
        if not encrypting_key:
            encrypting_key = click.prompt('Enter Encrypting Key',
                                          type=UMBRAL_PUBLIC_KEY_HEX)
        encrypting_key = bytes.fromhex(encrypting_key)  # TODO: Move / Validate

    # Init
    new_card = Card(character_flag=character_flag,
                    verifying_key=verifying_key,
                    encrypting_key=encrypting_key,
                    nickname=nickname)

    # Nickname
    if not force and not nickname:
        card_id_hex = new_card.id.hex()
        nickname = click.prompt('Enter nickname for card', default=card_id_hex)
        if nickname != card_id_hex:  # not the default
            nickname = nickname.strip()
            new_card.nickname = nickname

    # Save
    new_card.save()
    emitter.message(f'Saved new card {new_card}', color='green')
    paint_single_card(emitter=emitter, card=new_card)
Ejemplo n.º 13
0
 def generate_config(self, config_root, discovery_port):
     return FelixConfiguration.generate(
         password=get_nucypher_password(emitter=StdoutEmitter(), confirm=True),
         config_root=config_root,
         rest_host=self.host,
         rest_port=discovery_port,
         db_filepath=self.db_filepath,
         domain=self.domain,
         checksum_address=self.checksum_address,
         registry_filepath=self.registry_filepath,
         provider_uri=self.provider_uri,
         signer_uri=self.signer_uri,
         poa=self.poa)
Ejemplo n.º 14
0
def inspect(provider_uri, config_root, registry_infile, deployer_address, poa):
    """
    Echo owner information and bare contract metadata.
    """
    # Init
    emitter = StdoutEmitter()
    _ensure_config_root(config_root)
    _initialize_blockchain(poa, provider_uri)

    local_registry = establish_deployer_registry(
        emitter=emitter, registry_infile=registry_infile)
    paint_deployer_contract_inspection(emitter=emitter,
                                       registry=local_registry,
                                       deployer_address=deployer_address)
Ejemplo n.º 15
0
    def sync(self, show_progress: bool = False) -> None:

        sync_state = self.client.sync()
        if show_progress:
            import click
            # TODO: #1503 - It is possible that output has been redirected from a higher-level emitter.
            # TODO: #1503 - Use console logging instead of StdOutEmitter here.
            emitter = StdoutEmitter()

            emitter.echo(
                f"Syncing: {self.client.chain_name.capitalize()}. Waiting for sync to begin."
            )

            while not len(self.client.peers):
                emitter.echo("waiting for peers...")
                time.sleep(5)

            peer_count = len(self.client.peers)
            emitter.echo(
                f"Found {'an' if peer_count == 1 else peer_count} Ethereum peer{('s' if peer_count > 1 else '')}."
            )

            try:
                emitter.echo("Beginning sync...")
                initial_state = next(sync_state)
            except StopIteration:  # will occur if no syncing needs to happen
                emitter.echo("Local blockchain data is already synced.")
                return

            prior_state = initial_state
            total_blocks_to_sync = int(initial_state.get(
                'highestBlock', 0)) - int(initial_state.get('currentBlock', 0))
            with click.progressbar(length=total_blocks_to_sync,
                                   label="sync progress") as bar:
                for syncdata in sync_state:
                    if syncdata:
                        blocks_accomplished = int(
                            syncdata['currentBlock']) - int(
                                prior_state.get('currentBlock', 0))
                        bar.update(blocks_accomplished)
                        prior_state = syncdata
        else:
            try:
                for syncdata in sync_state:
                    self.client.log.info(
                        f"Syncing {syncdata['currentBlock']}/{syncdata['highestBlock']}"
                    )
            except TypeError:  # it's already synced
                return
        return
Ejemplo n.º 16
0
def test_rapid_deployment(token_economics, test_registry, tmpdir, get_random_checksum_address):
    compiler = SolidityCompiler()

    blockchain = _TesterBlockchain(eth_airdrop=False,
                                   test_accounts=4,
                                   compiler=compiler)

    # TODO: #1092 - TransactingPower
    blockchain.transacting_power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD,
                                                    account=blockchain.etherbase_account)
    blockchain.transacting_power.activate()
    deployer_address = blockchain.etherbase_account

    administrator = ContractAdministrator(deployer_address=deployer_address,
                                          registry=test_registry)

    administrator.deploy_network_contracts(emitter=StdoutEmitter(), interactive=False)

    all_yall = blockchain.unassigned_accounts

    # Start with some hard-coded cases...
    allocation_data = [{'checksum_address': all_yall[1],
                        'amount': token_economics.maximum_allowed_locked,
                        'lock_periods': token_economics.minimum_locked_periods},

                       {'checksum_address': all_yall[2],
                        'amount': token_economics.minimum_allowed_locked,
                        'lock_periods': token_economics.minimum_locked_periods},

                       {'checksum_address': all_yall[3],
                        'amount': token_economics.minimum_allowed_locked*100,
                        'lock_periods': token_economics.minimum_locked_periods},
                       ]

    # Pile on the rest
    for _ in range(NUMBER_OF_ALLOCATIONS_IN_TESTS - len(allocation_data)):
        checksum_address = get_random_checksum_address()
        amount = random.randint(token_economics.minimum_allowed_locked, token_economics.maximum_allowed_locked)
        duration = random.randint(token_economics.minimum_locked_periods, token_economics.maximum_rewarded_periods)
        random_allocation = {'checksum_address': checksum_address, 'amount': amount, 'lock_periods': duration}
        allocation_data.append(random_allocation)

    filepath = tmpdir / "allocations.json"
    with open(filepath, 'w') as f:
        json.dump(allocation_data, f)

    administrator.batch_deposits(allocation_data_filepath=str(filepath), interactive=False)

    minimum, default, maximum = 10, 20, 30
    administrator.set_fee_rate_range(minimum, default, maximum)
Ejemplo n.º 17
0
def download_registry(config_root, registry_outfile, force):
    """
    Download the latest registry.
    """
    # Init
    emitter = StdoutEmitter()
    _ensure_config_root(config_root)

    if not force:
        prompt = f"Fetch and download latest registry from {BaseContractRegistry.get_publication_endpoint()}?"
        click.confirm(prompt, abort=True)
    registry = InMemoryContractRegistry.from_latest_publication()
    output_filepath = registry.commit(filepath=registry_outfile,
                                      overwrite=force)
    emitter.message(
        f"Successfully downloaded latest registry to {output_filepath}")
Ejemplo n.º 18
0
def _list():
    """Show all character cards"""
    emitter = StdoutEmitter()
    card_directory = Card.CARD_DIR
    try:
        card_filepaths = os.listdir(card_directory)
    except FileNotFoundError:
        os.mkdir(Card.CARD_DIR)
        card_filepaths = os.listdir(card_directory)
    if not card_filepaths:
        emitter.error(
            f'No cards found at {card_directory}.  '
            f"To create one run 'nucypher {contacts.name} {create.name}'.")
    cards = list()
    for filename in card_filepaths:
        card = Card.load(filepath=Card.CARD_DIR / filename)
        cards.append(card)
    paint_cards(emitter=emitter, cards=cards, as_table=True)
Ejemplo n.º 19
0
def allocations(  # Admin Actor Options
        provider_uri,
        contract_name,
        config_root,
        poa,
        force,
        etherscan,
        hw_wallet,
        deployer_address,
        registry_infile,
        registry_outfile,
        dev,
        se_test_mode,

        # Other
        allocation_infile,
        allocation_outfile):
    """
    Deploy pre-allocation contracts.
    """
    # Init
    emitter = StdoutEmitter()
    _ensure_config_root(config_root)
    deployer_interface = _initialize_blockchain(poa, provider_uri)

    # Warnings
    _pre_launch_warnings(emitter, etherscan, hw_wallet)

    #
    # Make Authenticated Deployment Actor
    #
    ADMINISTRATOR, deployer_address, local_registry = _make_authenticated_deployment_actor(
        emitter, provider_uri, deployer_address, deployer_interface,
        contract_name, registry_infile, registry_outfile, hw_wallet, dev,
        force, se_test_mode)

    if not allocation_infile:
        allocation_infile = click.prompt("Enter allocation data filepath")
    ADMINISTRATOR.deploy_beneficiaries_from_file(
        allocation_data_filepath=allocation_infile,
        allocation_outfile=allocation_outfile,
        emitter=emitter,
        interactive=not force)
Ejemplo n.º 20
0
def nucypher_cli(click_config,
                 verbose,
                 mock_networking,
                 json_ipc,
                 no_logs,
                 quiet,
                 debug,
                 no_registry):

    # Session Emitter for pre and post character control engagement.
    if json_ipc:
        emitter = IPCStdoutEmitter(quiet=quiet, capture_stdout=NucypherClickConfig.capture_stdout)
    else:
        emitter = StdoutEmitter(quiet=quiet, capture_stdout=NucypherClickConfig.capture_stdout)

    NucypherClickConfig.emitter = emitter
    click_config.emitter(message=NUCYPHER_BANNER)

    # Logging
    if not no_logs:
        GlobalConsoleLogger.start_if_not_started()

    # CLI Session Configuration
    click_config.verbose = verbose
    click_config.mock_networking = mock_networking
    click_config.json_ipc = json_ipc
    click_config.no_logs = no_logs
    click_config.quiet = quiet
    click_config.no_registry = no_registry
    click_config.debug = debug

    # only used for testing outputs;
    # Redirects outputs to in-memory python containers.
    if mock_networking:
        click_config.emitter(message="WARNING: Mock networking is enabled")
        click_config.middleware = MockRestMiddleware()
    else:
        click_config.middleware = RestMiddleware()

    # Global Warnings
    if click_config.verbose:
        click_config.emitter("Verbose mode is enabled", color='blue')
Ejemplo n.º 21
0
    def set_options(self, mock_networking, no_registry, json_ipc, verbose,
                    quiet, no_logs, console_logs, file_logs, sentry_logs,
                    log_level, debug):

        # Session Emitter for pre and post character control engagement.
        if verbose and quiet:
            raise click.BadOptionUsage(
                option_name="quiet",
                message="--verbose and --quiet are mutually exclusive "
                "and cannot be used at the same time.")

        if verbose:
            verbosity = 2
        elif quiet:
            verbosity = 0
        else:
            verbosity = 1

        if json_ipc:
            emitter = JSONRPCStdoutEmitter(verbosity=verbosity)
        else:
            emitter = StdoutEmitter(verbosity=verbosity)

        self.attach_emitter(emitter)

        if verbose:
            self.emitter.message("Verbose mode is enabled", color='blue')

        # Logging

        if debug and no_logs:
            raise click.BadOptionUsage(
                option_name="no-logs",
                message="--debug and --no-logs cannot be used at the same time."
            )

        # Defaults
        if file_logs is None:
            file_logs = self.log_to_file
        if sentry_logs is None:
            sentry_logs = self.log_to_sentry

        if debug:
            console_logs = True
            file_logs = True
            sentry_logs = False
            log_level = 'debug'

        if no_logs:
            console_logs = False
            file_logs = False
            sentry_logs = False

        GlobalLoggerSettings.set_log_level(log_level_name=log_level)

        if console_logs:
            GlobalLoggerSettings.start_console_logging()
        if file_logs:
            GlobalLoggerSettings.start_text_file_logging()
            GlobalLoggerSettings.start_json_file_logging()
        if sentry_logs:
            GlobalLoggerSettings.start_sentry_logging(self.sentry_endpoint)

        # CLI Session Configuration
        self.mock_networking = mock_networking
        self.no_registry = no_registry
        self.debug = debug
        self.json_ipc = json_ipc

        # Only used for testing outputs;
        # Redirects outputs to in-memory python containers.
        if mock_networking:
            self.emitter.message("WARNING: Mock networking is enabled")
            self.middleware = MockRestMiddleware()
        else:
            self.middleware = RestMiddleware()
Ejemplo n.º 22
0
You should have received a copy of the GNU Affero General Public License
along with nucypher.  If not, see <https://www.gnu.org/licenses/>.
"""
import os
from decimal import Decimal

import click
import maya
from constant_sorrow.constants import NO_KNOWN_NODES

from nucypher.blockchain.eth.utils import datetime_at_period
from nucypher.characters.banners import NUCYPHER_BANNER
from nucypher.characters.control.emitters import StdoutEmitter
from nucypher.config.constants import SEEDNODES

emitter = StdoutEmitter()


def echo_version(ctx, param, value):
    if not value or ctx.resilient_parsing:
        return
    click.secho(NUCYPHER_BANNER, bold=True)
    ctx.exit()


def paint_new_installation_help(new_configuration,
                                federated_only: bool = False,
                                config_root=None,
                                config_file=None):
    character_config_class = new_configuration.__class__
    character_name = character_config_class._NAME.lower()
Ejemplo n.º 23
0
def test_emitter(mocker):
    # Note that this fixture does not capture console output.
    # Whether the output is captured or not is controlled by
    # the usage of the (built-in) `capsys` fixture or global PyTest run settings.
    return StdoutEmitter()
Ejemplo n.º 24
0
def protocol(ursula):
    emitter = StdoutEmitter()
    protocol = UrsulaCommandProtocol(ursula=ursula, emitter=emitter)
    return protocol
Ejemplo n.º 25
0
    def sign_and_broadcast_transaction(self,
                                       transaction_dict,
                                       transaction_name: str = "",
                                       confirmations: int = 0) -> dict:

        #
        # Setup
        #

        # TODO # 1754 - Move this to singleton - I do not approve... nor does Bogdan?
        if GlobalLoggerSettings._json_ipc:
            emitter = JSONRPCStdoutEmitter()
        else:
            emitter = StdoutEmitter()

        if self.transacting_power is READ_ONLY_INTERFACE:
            raise self.InterfaceError(str(READ_ONLY_INTERFACE))

        #
        # Sign
        #

        # TODO: Show the USD Price:  https://api.coinmarketcap.com/v1/ticker/ethereum/
        price = transaction_dict['gasPrice']
        cost_wei = price * transaction_dict['gas']
        cost = Web3.fromWei(cost_wei, 'gwei')
        if self.transacting_power.is_device:
            emitter.message(
                f'Confirm transaction {transaction_name} on hardware wallet... ({cost} gwei @ {price})',
                color='yellow')
        signed_raw_transaction = self.transacting_power.sign_transaction(
            transaction_dict)

        #
        # Broadcast
        #

        emitter.message(
            f'Broadcasting {transaction_name} Transaction ({cost} gwei @ {price})...',
            color='yellow')
        try:
            txhash = self.client.send_raw_transaction(
                signed_raw_transaction)  # <--- BROADCAST
        except (TestTransactionFailed, ValueError) as error:
            raise  # TODO: Unify with Transaction failed handling

        #
        # Receipt
        #

        try:  # TODO: Handle block confirmation exceptions
            receipt = self.client.wait_for_receipt(txhash,
                                                   timeout=self.TIMEOUT,
                                                   confirmations=confirmations)
        except TimeExhausted:
            # TODO: #1504 - Handle transaction timeout
            raise
        else:
            self.log.debug(
                f"[RECEIPT-{transaction_name}] | txhash: {receipt['transactionHash'].hex()}"
            )

        #
        # Confirmations
        #

        # Primary check
        transaction_status = receipt.get('status', UNKNOWN_TX_STATUS)
        if transaction_status == 0:
            failure = f"Transaction transmitted, but receipt returned status code 0. " \
                      f"Full receipt: \n {pprint.pformat(receipt, indent=2)}"
            raise self.InterfaceError(failure)

        if transaction_status is UNKNOWN_TX_STATUS:
            self.log.info(
                f"Unknown transaction status for {txhash} (receipt did not contain a status field)"
            )

            # Secondary check
            tx = self.client.get_transaction(txhash)
            if tx["gas"] == receipt["gasUsed"]:
                raise self.InterfaceError(
                    f"Transaction consumed 100% of transaction gas."
                    f"Full receipt: \n {pprint.pformat(receipt, indent=2)}")

        return receipt
Ejemplo n.º 26
0
from nucypher.blockchain.eth.agents import ContractAgency, StakingEscrowAgent, PolicyManagerAgent, NucypherTokenAgent
from nucypher.config.constants import NUCYPHER_ENVVAR_PROVIDER_URI
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
from nucypher.blockchain.eth.registry import InMemoryContractRegistry

from nucypher.characters.control.emitters import StdoutEmitter
from nucypher.utilities.logging import GlobalLoggerSettings

from constant_sorrow.constants import NO_BLOCKCHAIN_CONNECTION
from eth_utils import to_checksum_address

NO_BLOCKCHAIN_CONNECTION.bool_value(False)  # FIXME

GlobalLoggerSettings.start_console_logging()

emitter = StdoutEmitter(verbosity=2)

try:
    provider_uri = sys.argv[2]
except IndexError:
    provider_uri = os.getenv(NUCYPHER_ENVVAR_PROVIDER_URI)
    if not provider_uri:
        emitter.message("You have to pass a provider URI", color='red')
        sys.exit(-1)

try:
    network = sys.argv[1]
except IndexError:
    network = "ibex"

BlockchainInterfaceFactory.initialize_interface(provider_uri=provider_uri,
Ejemplo n.º 27
0
def deploy(action, poa, etherscan, provider_uri, gas, deployer_address,
           contract_name, allocation_infile, allocation_outfile,
           registry_infile, registry_outfile, value, target_address,
           config_root, hw_wallet, force, dev):
    """
    Manage contract and registry deployment.

    \b
    Actions
    -----------------------------------------------------------------------------
    contracts              Compile and deploy contracts.
    allocations            Deploy pre-allocation contracts.
    upgrade                Upgrade NuCypher existing proxy contract deployments.
    rollback               Rollback a proxy contract's target.
    inspect                Echo owner information and bare contract metadata.
    transfer-tokens        Transfer tokens from a contract to another address using the owner's address.
    transfer-ownership     Transfer ownership of contracts to another address.
    """

    emitter = StdoutEmitter()

    #
    # Validate
    #

    # Ensure config root exists, because we need a default place to put output files.
    config_root = config_root or DEFAULT_CONFIG_ROOT
    if not os.path.exists(config_root):
        os.makedirs(config_root)

    if not provider_uri:
        raise click.BadOptionUsage(
            message=f"--provider is required to deploy.",
            option_name="--provider")

    #
    # Pre-Launch Warnings
    #

    if not hw_wallet:
        emitter.echo("WARNING: --no-hw-wallet is enabled.", color='yellow')

    if etherscan:
        emitter.echo(
            "WARNING: --etherscan is enabled. "
            "A browser tab will be opened with deployed contracts and TXs as provided by Etherscan.",
            color='yellow')
    else:
        emitter.echo(
            "WARNING: --etherscan is disabled. "
            "If you want to see deployed contracts and TXs in your browser, activate --etherscan.",
            color='yellow')

    #
    # Connect to Blockchain
    #

    if not BlockchainInterfaceFactory.is_interface_initialized(
            provider_uri=provider_uri):
        # Note: For test compatibility.
        deployer_interface = BlockchainDeployerInterface(
            provider_uri=provider_uri, poa=poa)
        BlockchainInterfaceFactory.register_interface(
            interface=deployer_interface, sync=False, show_sync_progress=False)
    else:
        deployer_interface = BlockchainInterfaceFactory.get_interface(
            provider_uri=provider_uri)

    if action == "inspect":
        if registry_infile:
            registry = LocalContractRegistry(filepath=registry_infile)
        else:
            registry = InMemoryContractRegistry.from_latest_publication()
        administrator = ContractAdministrator(
            registry=registry, deployer_address=deployer_address)
        paint_deployer_contract_inspection(emitter=emitter,
                                           administrator=administrator)
        return  # Exit

    #
    # Establish Registry
    #

    # Establish a contract registry from disk if specified
    default_registry_filepath = os.path.join(
        DEFAULT_CONFIG_ROOT, BaseContractRegistry.REGISTRY_NAME)
    registry_filepath = (registry_outfile
                         or registry_infile) or default_registry_filepath
    if dev:
        # TODO: Need a way to detect a geth --dev registry filepath here. (then deprecate the --dev flag)
        registry_filepath = os.path.join(config_root,
                                         'dev_contract_registry.json')
    registry = LocalContractRegistry(filepath=registry_filepath)
    emitter.message(f"Configured to registry filepath {registry_filepath}")

    #
    # Make Authenticated Deployment Actor
    #

    # Verify Address & collect password
    if not deployer_address:
        prompt = "Select deployer account"
        deployer_address = select_client_account(emitter=emitter,
                                                 prompt=prompt,
                                                 provider_uri=provider_uri,
                                                 show_balances=False)

    if not force:
        click.confirm("Selected {} - Continue?".format(deployer_address),
                      abort=True)

    password = None
    if not hw_wallet and not deployer_interface.client.is_local:
        password = get_client_password(checksum_address=deployer_address)

    # Produce Actor
    ADMINISTRATOR = ContractAdministrator(registry=registry,
                                          client_password=password,
                                          deployer_address=deployer_address)

    # Verify ETH Balance
    emitter.echo(f"\n\nDeployer ETH balance: {ADMINISTRATOR.eth_balance}")
    if ADMINISTRATOR.eth_balance == 0:
        emitter.echo("Deployer address has no ETH.", color='red', bold=True)
        raise click.Abort()

    #
    # Action switch
    #

    if action == 'upgrade':
        if not contract_name:
            raise click.BadArgumentUsage(
                message="--contract-name is required when using --upgrade")
        existing_secret = click.prompt(
            'Enter existing contract upgrade secret', hide_input=True)
        new_secret = click.prompt('Enter new contract upgrade secret',
                                  hide_input=True,
                                  confirmation_prompt=True)
        ADMINISTRATOR.upgrade_contract(
            contract_name=contract_name,
            existing_plaintext_secret=existing_secret,
            new_plaintext_secret=new_secret)
        return  # Exit

    elif action == 'rollback':
        if not contract_name:
            raise click.BadArgumentUsage(
                message="--contract-name is required when using --rollback")
        existing_secret = click.prompt(
            'Enter existing contract upgrade secret', hide_input=True)
        new_secret = click.prompt('Enter new contract upgrade secret',
                                  hide_input=True,
                                  confirmation_prompt=True)
        ADMINISTRATOR.rollback_contract(
            contract_name=contract_name,
            existing_plaintext_secret=existing_secret,
            new_plaintext_secret=new_secret)
        return  # Exit

    elif action == "contracts":

        #
        # Deploy Single Contract (Amend Registry)
        #

        if contract_name:
            try:
                contract_deployer = ADMINISTRATOR.deployers[contract_name]
            except KeyError:
                message = f"No such contract {contract_name}. Available contracts are {ADMINISTRATOR.deployers.keys()}"
                emitter.echo(message, color='red', bold=True)
                raise click.Abort()
            else:
                emitter.echo(f"Deploying {contract_name}")
                if contract_deployer._upgradeable:
                    secret = ADMINISTRATOR.collect_deployment_secret(
                        deployer=contract_deployer)
                    receipts, agent = ADMINISTRATOR.deploy_contract(
                        contract_name=contract_name, plaintext_secret=secret)
                else:
                    receipts, agent = ADMINISTRATOR.deploy_contract(
                        contract_name=contract_name, gas_limit=gas)
                paint_contract_deployment(
                    contract_name=contract_name,
                    contract_address=agent.contract_address,
                    receipts=receipts,
                    emitter=emitter,
                    chain_name=deployer_interface.client.chain_name,
                    open_in_browser=etherscan)
            return  # Exit

        #
        # Deploy Automated Series (Create Registry)
        #

        # Confirm filesystem registry writes.
        if os.path.isfile(registry_filepath):
            emitter.echo(
                f"\nThere is an existing contract registry at {registry_filepath}.\n"
                f"Did you mean 'nucypher-deploy upgrade'?\n",
                color='yellow')
            click.confirm("*DESTROY* existing local registry and continue?",
                          abort=True)
            os.remove(registry_filepath)

        # Stage Deployment
        secrets = ADMINISTRATOR.collect_deployment_secrets()
        paint_staged_deployment(deployer_interface=deployer_interface,
                                administrator=ADMINISTRATOR,
                                emitter=emitter)

        # Confirm Trigger Deployment
        if not confirm_deployment(emitter=emitter,
                                  deployer_interface=deployer_interface):
            raise click.Abort()

        # Delay - Last chance to abort via KeyboardInterrupt
        paint_deployment_delay(emitter=emitter)

        # Execute Deployment
        deployment_receipts = ADMINISTRATOR.deploy_network_contracts(
            secrets=secrets,
            emitter=emitter,
            interactive=not force,
            etherscan=etherscan)

        # Paint outfile paths
        registry_outfile = registry_filepath
        emitter.echo('Generated registry {}'.format(registry_outfile),
                     bold=True,
                     color='blue')

        # Save transaction metadata
        receipts_filepath = ADMINISTRATOR.save_deployment_receipts(
            receipts=deployment_receipts)
        emitter.echo(f"Saved deployment receipts to {receipts_filepath}",
                     color='blue',
                     bold=True)
        return  # Exit

    elif action == "allocations":
        if not allocation_infile:
            allocation_infile = click.prompt("Enter allocation data filepath")
        click.confirm("Continue deploying and allocating?", abort=True)
        ADMINISTRATOR.deploy_beneficiaries_from_file(
            allocation_data_filepath=allocation_infile,
            allocation_outfile=allocation_outfile)
        return  # Exit

    elif action == "transfer-tokens":
        token_agent = ContractAgency.get_agent(NucypherTokenAgent,
                                               registry=registry)
        if not target_address:
            target_address = click.prompt("Enter recipient's checksum address",
                                          type=EIP55_CHECKSUM_ADDRESS)
        if not value:
            stake_value_range = click.FloatRange(min=0, clamp=False)
            value = NU.from_tokens(
                click.prompt(f"Enter value in NU", type=stake_value_range))

        click.confirm(
            f"Transfer {value} from {deployer_address} to {target_address}?",
            abort=True)
        receipt = token_agent.transfer(amount=value,
                                       sender_address=deployer_address,
                                       target_address=target_address)
        emitter.echo(f"OK | Receipt: {receipt['transactionHash'].hex()}")
        return  # Exit

    elif action == "transfer-ownership":
        if not target_address:
            target_address = click.prompt("Enter new owner's checksum address",
                                          type=EIP55_CHECKSUM_ADDRESS)

        if contract_name:
            try:
                contract_deployer_class = ADMINISTRATOR.deployers[
                    contract_name]
            except KeyError:
                message = f"No such contract {contract_name}. Available contracts are {ADMINISTRATOR.deployers.keys()}"
                emitter.echo(message, color='red', bold=True)
                raise click.Abort()
            else:
                contract_deployer = contract_deployer_class(
                    registry=ADMINISTRATOR.registry,
                    deployer_address=ADMINISTRATOR.deployer_address)
                receipt = contract_deployer.transfer_ownership(
                    new_owner=target_address, transaction_gas_limit=gas)
                emitter.ipc(receipt, request_id=0, duration=0)  # TODO: #1216
                return  # Exit
        else:
            receipts = ADMINISTRATOR.relinquish_ownership(
                new_owner=target_address, transaction_gas_limit=gas)
            emitter.ipc(receipts, request_id=0, duration=0)  # TODO: #1216
            return  # Exit

    else:
        raise click.BadArgumentUsage(message=f"Unknown action '{action}'")
Ejemplo n.º 28
0
    def sign_and_broadcast_transaction(
            self,
            transaction_dict,
            transaction_name: str = "",
            confirmations: int = 0,
            fire_and_forget: bool = False) -> Union[TxReceipt, HexBytes]:
        """
        Takes a transaction dictionary, signs it with the configured signer, then broadcasts the signed
        transaction using the ethereum provider's eth_sendRawTransaction RPC endpoint.
        Optionally blocks for receipt and confirmation with 'confirmations', and 'fire_and_forget' flags.

        If 'fire and forget' is True this method returns the transaction hash only, without waiting for a receipt -
        otherwise return the transaction receipt.

        """
        #
        # Setup
        #

        # TODO # 1754 - Move this to singleton - I do not approve... nor does Bogdan?
        if GlobalLoggerSettings._json_ipc:
            emitter = JSONRPCStdoutEmitter()
        else:
            emitter = StdoutEmitter()

        if self.transacting_power is READ_ONLY_INTERFACE:
            raise self.InterfaceError(str(READ_ONLY_INTERFACE))

        #
        # Sign
        #

        # TODO: Show the USD Price:  https://api.coinmarketcap.com/v1/ticker/ethereum/
        price = transaction_dict['gasPrice']
        price_gwei = Web3.fromWei(price, 'gwei')
        cost_wei = price * transaction_dict['gas']
        cost = Web3.fromWei(cost_wei, 'ether')

        if self.transacting_power.is_device:
            emitter.message(
                f'Confirm transaction {transaction_name} on hardware wallet... '
                f'({cost} ETH @ {price_gwei} gwei)',
                color='yellow')
        signed_raw_transaction = self.transacting_power.sign_transaction(
            transaction_dict)

        #
        # Broadcast
        #
        emitter.message(
            f'Broadcasting {transaction_name} Transaction ({cost} ETH @ {price_gwei} gwei)...',
            color='yellow')
        try:
            txhash = self.client.send_raw_transaction(
                signed_raw_transaction)  # <--- BROADCAST
        except (TestTransactionFailed, ValueError):
            raise  # TODO: Unify with Transaction failed handling -- Entry point for _handle_failed_transaction
        else:
            if fire_and_forget:
                return txhash

        #
        # Receipt
        #

        try:  # TODO: Handle block confirmation exceptions
            receipt = self.client.wait_for_receipt(txhash,
                                                   timeout=self.TIMEOUT,
                                                   confirmations=confirmations)
        except TimeExhausted:
            # TODO: #1504 - Handle transaction timeout
            raise
        else:
            self.log.debug(
                f"[RECEIPT-{transaction_name}] | txhash: {receipt['transactionHash'].hex()}"
            )

        #
        # Confirmations
        #

        # Primary check
        transaction_status = receipt.get('status', UNKNOWN_TX_STATUS)
        if transaction_status == 0:
            failure = f"Transaction transmitted, but receipt returned status code 0. " \
                      f"Full receipt: \n {pprint.pformat(receipt, indent=2)}"
            raise self.InterfaceError(failure)

        if transaction_status is UNKNOWN_TX_STATUS:
            self.log.info(
                f"Unknown transaction status for {txhash} (receipt did not contain a status field)"
            )

            # Secondary check
            tx = self.client.get_transaction(txhash)
            if tx["gas"] == receipt["gasUsed"]:
                raise self.InterfaceError(
                    f"Transaction consumed 100% of transaction gas."
                    f"Full receipt: \n {pprint.pformat(receipt, indent=2)}")

        return receipt
Ejemplo n.º 29
0
    def __init__(self, json_ipc: bool, verbose: bool, quiet: bool,
                 no_logs: bool, console_logs: bool, file_logs: bool,
                 sentry_logs: bool, log_level: bool, debug: bool):

        self.log = Logger(self.__class__.__name__)

        # Session Emitter for pre and post character control engagement.
        if verbose and quiet:
            raise click.BadOptionUsage(
                option_name="quiet",
                message="--verbose and --quiet are mutually exclusive "
                "and cannot be used at the same time.")

        if verbose:
            GroupGeneralConfig.verbosity = 2
        elif quiet:
            GroupGeneralConfig.verbosity = 0
        else:
            GroupGeneralConfig.verbosity = 1

        if json_ipc:
            GlobalLoggerSettings._json_ipc = True  # TODO #1754
            emitter = JSONRPCStdoutEmitter(
                verbosity=GroupGeneralConfig.verbosity)
        else:
            emitter = StdoutEmitter(verbosity=GroupGeneralConfig.verbosity)

        self.emitter = emitter

        if verbose:
            self.emitter.message("Verbose mode is enabled", color='blue')

        # Logging
        if debug and no_logs:
            message = "--debug and --no-logs cannot be used at the same time."
            raise click.BadOptionUsage(option_name="no-logs", message=message)

        # Defaults
        if file_logs is None:
            file_logs = self.log_to_file
        if sentry_logs is None:
            sentry_logs = self.log_to_sentry

        if debug:
            console_logs = True
            file_logs = True
            sentry_logs = False
            log_level = 'debug'

        if no_logs:
            console_logs = False
            file_logs = False
            sentry_logs = False
        if json_ipc:
            console_logs = False

        GlobalLoggerSettings.set_log_level(log_level_name=log_level)

        if console_logs:
            GlobalLoggerSettings.start_console_logging()
        if file_logs:
            GlobalLoggerSettings.start_text_file_logging()
            GlobalLoggerSettings.start_json_file_logging()
        if sentry_logs:
            GlobalLoggerSettings.start_sentry_logging(self.sentry_endpoint)
        if json_ipc:
            GlobalLoggerSettings.stop_console_logging()  # JSON-RPC Protection

        self.debug = debug
        self.json_ipc = json_ipc
Ejemplo n.º 30
0
def contracts(  # Admin Actor Options
        provider_uri,
        contract_name,
        config_root,
        poa,
        force,
        etherscan,
        hw_wallet,
        deployer_address,
        registry_infile,
        registry_outfile,
        dev,
        se_test_mode,

        # Other
        bare,
        gas,
        ignore_deployed):
    """
    Compile and deploy contracts.
    """
    # Init
    emitter = StdoutEmitter()
    _ensure_config_root(config_root)
    deployer_interface = _initialize_blockchain(poa, provider_uri)

    # Warnings
    _pre_launch_warnings(emitter, etherscan, hw_wallet)

    #
    # Make Authenticated Deployment Actor
    #
    ADMINISTRATOR, deployer_address, local_registry = _make_authenticated_deployment_actor(
        emitter, provider_uri, deployer_address, deployer_interface,
        contract_name, registry_infile, registry_outfile, hw_wallet, dev,
        force, se_test_mode)

    #
    # Deploy Single Contract (Amend Registry)
    #

    if contract_name:
        try:
            contract_deployer = ADMINISTRATOR.deployers[contract_name]
        except KeyError:
            message = f"No such contract {contract_name}. Available contracts are {ADMINISTRATOR.deployers.keys()}"
            emitter.echo(message, color='red', bold=True)
            raise click.Abort()

        # Deploy
        emitter.echo(f"Deploying {contract_name}")
        if contract_deployer._upgradeable and not bare:
            # NOTE: Bare deployments do not engage the proxy contract
            secret = ADMINISTRATOR.collect_deployment_secret(
                deployer=contract_deployer)
            receipts, agent = ADMINISTRATOR.deploy_contract(
                contract_name=contract_name,
                plaintext_secret=secret,
                gas_limit=gas,
                bare=bare,
                ignore_deployed=ignore_deployed)
        else:
            # Non-Upgradeable or Bare
            receipts, agent = ADMINISTRATOR.deploy_contract(
                contract_name=contract_name,
                gas_limit=gas,
                bare=bare,
                ignore_deployed=ignore_deployed)

        # Report
        paint_contract_deployment(
            contract_name=contract_name,
            contract_address=agent.contract_address,
            receipts=receipts,
            emitter=emitter,
            chain_name=deployer_interface.client.chain_name,
            open_in_browser=etherscan)
        return  # Exit

    #
    # Deploy Automated Series (Create Registry)
    #

    # Confirm filesystem registry writes.
    if os.path.isfile(local_registry.filepath):
        emitter.echo(
            f"\nThere is an existing contract registry at {local_registry.filepath}.\n"
            f"Did you mean 'nucypher-deploy upgrade'?\n",
            color='yellow')
        click.confirm("*DESTROY* existing local registry and continue?",
                      abort=True)
        os.remove(local_registry.filepath)

    # Stage Deployment
    secrets = ADMINISTRATOR.collect_deployment_secrets()
    paint_staged_deployment(deployer_interface=deployer_interface,
                            administrator=ADMINISTRATOR,
                            emitter=emitter)

    # Confirm Trigger Deployment
    if not confirm_deployment(emitter=emitter,
                              deployer_interface=deployer_interface):
        raise click.Abort()

    # Delay - Last chance to abort via KeyboardInterrupt
    paint_deployment_delay(emitter=emitter)

    # Execute Deployment
    deployment_receipts = ADMINISTRATOR.deploy_network_contracts(
        secrets=secrets,
        emitter=emitter,
        interactive=not force,
        etherscan=etherscan,
        ignore_deployed=ignore_deployed)

    # Paint outfile paths
    registry_outfile = local_registry.filepath
    emitter.echo('Generated registry {}'.format(registry_outfile),
                 bold=True,
                 color='blue')

    # Save transaction metadata
    receipts_filepath = ADMINISTRATOR.save_deployment_receipts(
        receipts=deployment_receipts)
    emitter.echo(f"Saved deployment receipts to {receipts_filepath}",
                 color='blue',
                 bold=True)