def multisig(general_config, actor_options, action, proposal): """ Perform operations via a MultiSig contract """ # Init emitter = general_config.emitter _ensure_config_root(actor_options.config_root) blockchain = _initialize_blockchain(poa=actor_options.poa, provider_uri=actor_options.provider_uri, emitter=emitter, ignore_solidity_check=actor_options.ignore_solididty_check, gas_strategy=actor_options.gas_strategy) local_registry = establish_deployer_registry(emitter=emitter, use_existing_registry=True, ) # Warnings # _pre_launch_warnings(emitter, etherscan, hw_wallet) multisig_agent = ContractAgency.get_agent(MultiSigAgent, registry=local_registry, provider_uri=actor_options.provider_uri) token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=local_registry) if action == 'inspect': paint_multisig_contract_info(emitter, multisig_agent, token_agent) elif action == 'sign': if not proposal: raise ValueError("multisig sign requires the use of --proposal") with open(proposal) as json_file: proposal = json.load(json_file) executive_summary = proposal['parameters'] name, version, address, abi = local_registry.search(contract_address=executive_summary['target_address']) # TODO: This assumes that we're always signing proxy retargetting. For the moment is true. proxy_contract = blockchain.client.w3.eth.contract(abi=abi, address=address, version=version, ContractFactoryClass=blockchain._contract_factory) paint_multisig_proposed_transaction(emitter, proposal, proxy_contract) click.confirm("Proceed with signing?", abort=True) # TODO: Blocked by lack of support to EIP191 - #1566 elif action == 'execute': pass # TODO
def create_actor(self, emitter): _ensure_config_root(self.config_root) deployer_interface = _initialize_blockchain(poa=self.poa, provider_uri=self.provider_uri, emitter=emitter, ignore_solidity_check=self.ignore_solidity_check, gas_strategy=self.gas_strategy) # Warnings _pre_launch_warnings(emitter, self.etherscan, self.hw_wallet) # # Establish Registry # local_registry = establish_deployer_registry(emitter=emitter, use_existing_registry=bool(self.contract_name), registry_infile=self.registry_infile, registry_outfile=self.registry_outfile, dev=self.dev) # # Make Authenticated Deployment Actor # # Verify Address & collect password deployer_address = self.deployer_address if not deployer_address: prompt = "Select deployer account" deployer_address = select_client_account(emitter=emitter, prompt=prompt, provider_uri=self.provider_uri, show_balances=False) if not self.force: click.confirm("Selected {} - Continue?".format(deployer_address), abort=True) password = None if not self.hw_wallet and not deployer_interface.client.is_local: password = get_client_password(checksum_address=deployer_address) # Produce Actor ADMINISTRATOR = ContractAdministrator(registry=local_registry, client_password=password, deployer_address=deployer_address, staking_escrow_test_mode=self.se_test_mode) # 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() return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
def inspect(general_config, provider_uri, config_root, registry_infile, deployer_address, poa): """ Echo owner information and bare contract metadata. """ # Init emitter = general_config.emitter _ensure_config_root(config_root) _initialize_blockchain(poa, provider_uri, emitter) local_registry = establish_deployer_registry(emitter=emitter, registry_infile=registry_infile, download_registry=not bool(registry_infile)) paint_deployer_contract_inspection(emitter=emitter, registry=local_registry, deployer_address=deployer_address)
def _make_authenticated_deployment_actor(emitter, provider_uri, deployer_address, deployer_interface, contract_name, registry_infile, registry_outfile, hw_wallet, dev, force, se_test_mode): # # Establish Registry # local_registry = establish_deployer_registry( emitter=emitter, use_existing_registry=bool(contract_name), registry_infile=registry_infile, registry_outfile=registry_outfile, dev=dev) # # 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=local_registry, client_password=password, deployer_address=deployer_address, staking_escrow_test_mode=se_test_mode) # 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() return ADMINISTRATOR, deployer_address, local_registry
def deploy(action, poa, etherscan, provider_uri, gas, deployer_address, contract_name, allocation_infile, allocation_outfile, registry_infile, registry_outfile, value, target_address, retarget, bare, 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) # # 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') if action == "download-registry": if not force: prompt = f"Fetch and download latest registry from {BaseContractRegistry.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}") return # Exit # # Connect to Blockchain # if not provider_uri: raise click.BadOptionUsage( message=f"--provider is required to deploy.", option_name="--provider") 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 # local_registry = establish_deployer_registry( emitter=emitter, use_existing_registry=bool(contract_name), registry_infile=registry_infile, registry_outfile=registry_outfile, dev=dev) # # 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=local_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) if retarget: if not target_address: raise click.BadArgumentUsage( message="--target-address is required when using --retarget" ) if not force: click.confirm( f"Confirm re-target {contract_name}'s proxy to {target_address}?", abort=True) receipt = ADMINISTRATOR.retarget_proxy( contract_name=contract_name, target_address=target_address, existing_plaintext_secret=existing_secret, new_plaintext_secret=new_secret) emitter.message( f"Successfully re-targeted {contract_name} proxy to {target_address}", color='green') paint_receipt_summary(emitter=emitter, receipt=receipt) return # Exit else: if not force: click.confirm( f"Confirm deploy new version of {contract_name} and retarget proxy?", abort=True) receipts = ADMINISTRATOR.upgrade_contract( contract_name=contract_name, existing_plaintext_secret=existing_secret, new_plaintext_secret=new_secret) emitter.message( f"Successfully deployed and upgraded {contract_name}", color='green') for name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt) 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() # 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) 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=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()}") 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}'")