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}'")
def contracts(general_config, actor_options, bare, gas, ignore_deployed): """ Compile and deploy contracts. """ # Init emitter = general_config.emitter ADMINISTRATOR, _, deployer_interface, local_registry = actor_options.create_actor( emitter) # # Deploy Single Contract (Amend Registry) # contract_name = actor_options.contract_name 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=actor_options.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 actor_options.force, etherscan=actor_options.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)
def deploy(action, poa, etherscan, provider_uri, gas, deployer_address, contract_name, allocation_infile, allocation_outfile, registry_infile, registry_outfile, amount, recipient_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. status Echo owner information and bare contract metadata. transfer-tokens Transfer tokens to another 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) # # 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 Registry # # Establish a contract registry from disk if specified registry_filepath = registry_outfile or registry_infile if dev: # TODO: Need a way to detect a geth--dev registry filepath here. (then deprecate the --dev flag) registry_filepath = os.path.join(DEFAULT_CONFIG_ROOT, 'dev_contract_registry.json') registry = EthereumContractRegistry(registry_filepath=registry_filepath) emitter.echo(f"Using contract registry filepath {registry.filepath}") # # Connect to Blockchain # blockchain = BlockchainDeployerInterface(provider_uri=provider_uri, poa=poa, registry=registry) try: blockchain.connect(fetch_registry=False, sync_now=False) except BlockchainDeployerInterface.ConnectionFailed as e: emitter.echo(str(e), color='red', bold=True) raise click.Abort() # # Make Authenticated Deployment Actor # # Verify Address & collect password if not deployer_address: prompt = "Select deployer account" deployer_address = select_client_account(emitter=emitter, blockchain=blockchain, prompt=prompt) if not force: click.confirm("Selected {} - Continue?".format(deployer_address), abort=True) password = None if not hw_wallet and not blockchain.client.is_local: password = get_client_password(checksum_address=deployer_address) # Produce Actor DEPLOYER = DeployerActor(blockchain=blockchain, client_password=password, deployer_address=deployer_address) # Verify ETH Balance emitter.echo(f"\n\nDeployer ETH balance: {DEPLOYER.eth_balance}") if DEPLOYER.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) DEPLOYER.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) DEPLOYER.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 = DEPLOYER.deployers[contract_name] except KeyError: message = f"No such contract {contract_name}. Available contracts are {DEPLOYER.deployers.keys()}" emitter.echo(message, color='red', bold=True) raise click.Abort() else: emitter.echo(f"Deploying {contract_name}") if contract_deployer._upgradeable: secret = DEPLOYER.collect_deployment_secret( deployer=contract_deployer) receipts, agent = DEPLOYER.deploy_contract( contract_name=contract_name, plaintext_secret=secret) else: receipts, agent = DEPLOYER.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=blockchain.client.chain_name, open_in_browser=etherscan) return # Exit # # Deploy Automated Series (Create Registry) # # Confirm filesystem registry writes. registry_filepath = DEPLOYER.blockchain.registry.filepath 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 = DEPLOYER.collect_deployment_secrets() paint_staged_deployment(deployer=DEPLOYER, emitter=emitter) # Confirm Trigger Deployment if not actions.confirm_deployment(emitter=emitter, deployer=DEPLOYER): raise click.Abort() # Delay - Last chance to abort via KeyboardInterrupt paint_deployment_delay(emitter=emitter) # Execute Deployment deployment_receipts = DEPLOYER.deploy_network_contracts( secrets=secrets, emitter=emitter, interactive=not force, etherscan=etherscan) # Paint outfile paths registry_outfile = DEPLOYER.blockchain.registry.filepath emitter.echo('Generated registry {}'.format(registry_outfile), bold=True, color='blue') # Save transaction metadata receipts_filepath = DEPLOYER.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) DEPLOYER.deploy_beneficiaries_from_file( allocation_data_filepath=allocation_infile, allocation_outfile=allocation_outfile) return # Exit elif action == "transfer": token_agent = NucypherTokenAgent(blockchain=blockchain) missing_options = list() if recipient_address is None: missing_options.append("--recipient-address") if amount is None: missing_options.append("--amount") if missing_options: raise click.BadOptionUsage( f"Need {' and '.join(missing_options)} to transfer tokens.") click.confirm( f"Transfer {amount} from {deployer_address} to {recipient_address}?", abort=True) receipt = token_agent.transfer(amount=amount, sender_address=deployer_address, target_address=recipient_address) emitter.echo(f"OK | Receipt: {receipt['transactionHash'].hex()}") return # Exit else: raise click.BadArgumentUsage(message=f"Unknown action '{action}'")
def contracts(general_config, actor_options, mode, activate, gas, ignore_deployed, confirmations, parameters): """ Compile and deploy contracts. """ # Init emitter = general_config.emitter ADMINISTRATOR, _, deployer_interface, local_registry = actor_options.create_actor(emitter) chain_name = deployer_interface.client.chain_name deployment_parameters = {} if parameters: with open(parameters) as json_file: deployment_parameters = json.load(json_file) # # Deploy Single Contract (Amend Registry) # contract_name = actor_options.contract_name deployment_mode = constants.__getattr__(mode.upper()) # TODO: constant sorrow 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() if activate: # For the moment, only StakingEscrow can be activated staking_escrow_deployer = contract_deployer_class(registry=ADMINISTRATOR.registry, deployer_address=ADMINISTRATOR.deployer_address) if contract_name != STAKING_ESCROW_CONTRACT_NAME or not staking_escrow_deployer.ready_to_activate: raise click.BadOptionUsage(option_name="--activate", message=f"You can only activate an idle instance of {STAKING_ESCROW_CONTRACT_NAME}") click.confirm(f"Activate {STAKING_ESCROW_CONTRACT_NAME} at " f"{staking_escrow_deployer._get_deployed_contract().address}?", abort=True) receipts = staking_escrow_deployer.activate() for tx_name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt, chain_name=chain_name, transaction_type=tx_name) return # Exit # Deploy emitter.echo(f"Deploying {contract_name}") receipts, agent = ADMINISTRATOR.deploy_contract(contract_name=contract_name, gas_limit=gas, deployment_mode=deployment_mode, ignore_deployed=ignore_deployed, confirmations=confirmations, deployment_parameters=deployment_parameters) # Report paint_contract_deployment(contract_name=contract_name, contract_address=agent.contract_address, receipts=receipts, emitter=emitter, chain_name=chain_name, open_in_browser=actor_options.etherscan) return # Exit # # Deploy Automated Series (Create Registry) # if deployment_mode is not FULL: raise click.BadOptionUsage(option_name='--mode', message="Only 'full' mode is supported when deploying all network contracts") # 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 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(emitter=emitter, interactive=not actor_options.force, etherscan=actor_options.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)
def contracts( # Admin Actor Options provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address, registry_infile, registry_outfile, dev, # Other bare, gas): """ 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) # # 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) else: # Non-Upgradeable or Bare receipts, agent = ADMINISTRATOR.deploy_contract( contract_name=contract_name, gas_limit=gas, bare=bare) # 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) # 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)