def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig): """ Upgrade NuCypher existing proxy contract deployments. """ # Init emitter = general_config.emitter ADMINISTRATOR, _, _, registry = actor_options.create_actor(emitter, is_multisig=bool(multisig)) # FIXME: Workaround for building MultiSig TXs contract_name = actor_options.contract_name if not contract_name: raise click.BadArgumentUsage(message="--contract-name is required when using --upgrade") if multisig: if not target_address: raise click.BadArgumentUsage(message="--multisig requires using --target-address.") if not actor_options.force: click.confirm(f"Confirm building a re-target transaction for {contract_name}'s proxy to {target_address}?", abort=True) transaction = ADMINISTRATOR.retarget_proxy(contract_name=contract_name, target_address=target_address, just_build_transaction=True) trustee_address = select_client_account(emitter=emitter, prompt="Select trustee address", provider_uri=actor_options.provider_uri, show_balances=False) if not actor_options.force: click.confirm(f"Selected {trustee_address} - Continue?", abort=True) trustee = Trustee(registry=registry, checksum_address=trustee_address) transaction_proposal = trustee.create_transaction_proposal(transaction) emitter.message(f"Transaction to retarget {contract_name} proxy to {target_address} was built:", color='green') paint_multisig_proposed_transaction(emitter, transaction_proposal) # TODO: Show decoded function too filepath = f'proposal-{trustee.multisig_agent.contract_address[:8]}-TX-{transaction_proposal.nonce}.json' transaction_proposal.write(filepath=filepath) emitter.echo(f"Saved proposal to {filepath}", color='blue', bold=True) elif retarget: if not target_address: raise click.BadArgumentUsage(message="--target-address is required when using --retarget") if not actor_options.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) emitter.message(f"Successfully re-targeted {contract_name} proxy to {target_address}", color='green') paint_receipt_summary(emitter=emitter, receipt=receipt) else: if not actor_options.force: click.confirm(f"Confirm deploy new version of {contract_name} and retarget proxy?", abort=True) receipts = ADMINISTRATOR.upgrade_contract(contract_name=contract_name, ignore_deployed=ignore_deployed) emitter.message(f"Successfully deployed and upgraded {contract_name}", color='green') for name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt)
def __create_trustee(self, registry, transacting: bool = False) -> Trustee: client_password = None is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri) if transacting and not self.hw_wallet and not is_clef: client_password = get_client_password(checksum_address=self.checksum_address) trustee = Trustee(checksum_address=self.checksum_address, registry=registry, client_password=client_password) return trustee
def __create_trustee(self, registry, transacting: bool = False) -> Trustee: client_password = None if transacting and not self.hw_wallet: client_password = get_client_password( checksum_address=self.checksum_address) trustee = Trustee(checksum_address=self.checksum_address, registry=registry, client_password=client_password) return trustee
def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig, confirmations): """Upgrade NuCypher existing proxy contract deployments.""" # # Setup # emitter = general_config.emitter ADMINISTRATOR, deployer_address, blockchain, local_registry = actor_options.create_actor(emitter, is_multisig=bool(multisig)) # FIXME: Workaround for building MultiSig TXs | NRN # # Pre-flight # contract_name = actor_options.contract_name if not contract_name: raise click.BadArgumentUsage(message="--contract-name is required when using --upgrade") try: # Check contract name exists Deployer = ADMINISTRATOR.deployers[contract_name] except KeyError: message = UNKNOWN_CONTRACT_NAME.format(contract_name=contract_name, constants=ADMINISTRATOR.deployers.keys()) emitter.echo(message, color='red', bold=True) raise click.Abort() deployer = Deployer(registry=local_registry) # Check deployer address is owner if Deployer._ownable and deployer_address != deployer.owner: # blockchain read emitter.echo(DEPLOYER_IS_NOT_OWNER.format(deployer_address=deployer_address, contract_name=contract_name, agent=deployer.make_agent())) raise click.Abort() else: emitter.echo('✓ Verified deployer address as contract owner', color='green') # # Business # if multisig: if not target_address: raise click.BadArgumentUsage(message="--multisig requires using --target-address.") if not actor_options.force: click.confirm(CONFIRM_BUILD_RETARGET_TRANSACTION.format(contract_name=contract_name, target_address=target_address), abort=True) transaction = ADMINISTRATOR.retarget_proxy(contract_name=contract_name, target_address=target_address, just_build_transaction=True, confirmations=confirmations) trustee_address = select_client_account(emitter=emitter, prompt="Select trustee address", provider_uri=actor_options.provider_uri, show_eth_balance=False, show_nu_balance=False, show_staking=False) if not actor_options.force: click.confirm(CONFIRM_SELECTED_ACCOUNT.format(address=trustee_address), abort=True) trustee = Trustee(registry=local_registry, checksum_address=trustee_address) transaction_proposal = trustee.create_transaction_proposal(transaction) message = SUCCESSFUL_RETARGET_TX_BUILT.format(contract_name=contract_name, target_address=target_address) emitter.message(message, color='green') paint_multisig_proposed_transaction(emitter, transaction_proposal) # TODO: Show decoded function too filepath = f'proposal-{trustee.multisig_agent.contract_address[:8]}-TX-{transaction_proposal.nonce}.json' transaction_proposal.write(filepath=filepath) emitter.echo(SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL.format(filepath=filepath), color='blue', bold=True) return # Exit elif retarget: if not target_address: raise click.BadArgumentUsage(message="--target-address is required when using --retarget") if not actor_options.force: click.confirm(CONFIRM_RETARGET.format(contract_name=contract_name, target_address=target_address), abort=True) receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,target_address=target_address, confirmations=confirmations) message = SUCCESSFUL_RETARGET.format(contract_name=contract_name, target_address=target_address) emitter.message(message, color='green') paint_receipt_summary(emitter=emitter, receipt=receipt) return # Exit else: github_registry = establish_deployer_registry(emitter=emitter, download_registry=True, network=actor_options.network) if not actor_options.force: # Check for human verification of versioned upgrade details click.confirm(CONFIRM_BEGIN_UPGRADE.format(contract_name=contract_name), abort=True) if deployer._ownable: # Only ownable + upgradeable contracts apply verify_upgrade_details(blockchain=blockchain, registry=github_registry, deployer=deployer) # Success receipts = ADMINISTRATOR.upgrade_contract(contract_name=contract_name, ignore_deployed=ignore_deployed, confirmations=confirmations) emitter.message(SUCCESSFUL_UPGRADE.format(contract_name=contract_name), color='green') for name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt) emitter.echo(REGISTRY_PUBLICATION_HINT.format(contract_name=contract_name, local_registry=local_registry, network=actor_options.network), color='blue') emitter.echo(ETHERSCAN_VERIFY_HINT.format(solc_version=SOLIDITY_COMPILER_VERSION), color='blue') return # Exit
def test_trustee_proposes_multisig_management_operations( testerchain, test_registry): origin = testerchain.etherbase_account multisig_deployer = MultiSigDeployer(deployer_address=origin, registry=test_registry) threshold = 2 owners = testerchain.unassigned_accounts[0:3] receipts = multisig_deployer.deploy(threshold=threshold, owners=owners) for step in multisig_deployer.deployment_steps: assert receipts[step]['status'] == 1 multisig_agent = multisig_deployer.make_agent() # type: MultiSigAgent trustee_address = testerchain.unassigned_accounts[-1] trustee = Trustee(checksum_address=trustee_address, registry=test_registry) # Propose changing threshold # FIXME: I had to mock the gas_price property of EthereumTesterClient because I'm unable to set a free gas strategy with patch( 'nucypher.blockchain.eth.clients.EthereumTesterClient.gas_price', new_callable=PropertyMock) as mock_ethtester: mock_ethtester.return_value = 0 proposal = trustee.propose_changing_threshold(new_threshold=1) assert proposal.trustee_address == trustee_address assert proposal.target_address == multisig_agent.contract_address assert proposal.nonce == multisig_agent.nonce assert proposal.value == 0 contract_function, params = proposal.decode_transaction_data( registry=test_registry) assert list(params.values()) == [ 1 ] # The new threshold is the only parameter in the call # Propose adding new owner new_owner = testerchain.unassigned_accounts[4] with patch( 'nucypher.blockchain.eth.clients.EthereumTesterClient.gas_price', new_callable=PropertyMock) as mock_ethtester: mock_ethtester.return_value = 0 proposal = trustee.propose_adding_owner(new_owner_address=new_owner, evidence=None) assert proposal.trustee_address == trustee_address assert proposal.target_address == multisig_agent.contract_address assert proposal.nonce == multisig_agent.nonce assert proposal.value == 0 contract_function, params = proposal.decode_transaction_data( registry=test_registry) assert list(params.values()) == [ new_owner ] # The new owner is the only parameter in the call # Propose removing owner evicted_owner = testerchain.unassigned_accounts[1] with patch( 'nucypher.blockchain.eth.clients.EthereumTesterClient.gas_price', new_callable=PropertyMock) as mock_ethtester: mock_ethtester.return_value = 0 proposal = trustee.propose_removing_owner(evicted_owner) assert proposal.trustee_address == trustee_address assert proposal.target_address == multisig_agent.contract_address assert proposal.nonce == multisig_agent.nonce assert proposal.value == 0 contract_function, params = proposal.decode_transaction_data( registry=test_registry) assert list(params.values()) == [ evicted_owner ] # The owner to remove is the only parameter in the call
def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig): """ Upgrade NuCypher existing proxy contract deployments. """ # Init emitter = general_config.emitter ADMINISTRATOR, _, _, registry = actor_options.create_actor( emitter, is_multisig=bool( multisig)) # FIXME: Workaround for building MultiSig TXs contract_name = actor_options.contract_name if not contract_name: raise click.BadArgumentUsage( message="--contract-name is required when using --upgrade") if multisig: if not target_address: raise click.BadArgumentUsage( message="--multisig requires using --target-address.") if not actor_options.force: click.confirm(CONFIRM_BUILD_RETARGET_TRANSACTION.format( contract_name=contract_name, target_address=target_address), abort=True) transaction = ADMINISTRATOR.retarget_proxy( contract_name=contract_name, target_address=target_address, just_build_transaction=True) trustee_address = select_client_account( emitter=emitter, prompt="Select trustee address", provider_uri=actor_options.provider_uri, show_eth_balance=False, show_nu_balance=False, show_staking=False) if not actor_options.force: click.confirm( CONFIRM_SELECTED_ACCOUNT.format(address=trustee_address), abort=True) trustee = Trustee(registry=registry, checksum_address=trustee_address) transaction_proposal = trustee.create_transaction_proposal(transaction) message = SUCCESSFUL_RETARGET_TX_BUILT.format( contract_name=contract_name, target_address=target_address) emitter.message(message, color='green') paint_multisig_proposed_transaction( emitter, transaction_proposal) # TODO: Show decoded function too filepath = f'proposal-{trustee.multisig_agent.contract_address[:8]}-TX-{transaction_proposal.nonce}.json' transaction_proposal.write(filepath=filepath) emitter.echo( SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL.format(filepath=filepath), color='blue', bold=True) elif retarget: if not target_address: raise click.BadArgumentUsage( message="--target-address is required when using --retarget") if not actor_options.force: click.confirm(CONFIRM_RETARGET.format( contract_name=contract_name, target_address=target_address), abort=True) receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name, target_address=target_address) message = SUCCESSFUL_RETARGET.format(contract_name=contract_name, target_address=target_address) emitter.message(message, color='green') paint_receipt_summary(emitter=emitter, receipt=receipt) else: if not actor_options.force: click.confirm( CONFIRM_BEGIN_UPGRADE.format(contract_name=contract_name), abort=True) receipts = ADMINISTRATOR.upgrade_contract( contract_name=contract_name, ignore_deployed=ignore_deployed) emitter.message(SUCCESSFUL_UPGRADE.format(contract_name=contract_name), color='green') for name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt)
def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig): """ Upgrade NuCypher existing proxy contract deployments. """ # Init emitter = general_config.emitter ADMINISTRATOR, _, _, registry = actor_options.create_actor(emitter) contract_name = actor_options.contract_name 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 multisig: if not target_address: raise click.BadArgumentUsage( message="--multisig requires using --target-address.") if not actor_options.force: click.confirm( f"Confirm building a re-target transaction for {contract_name}'s proxy to {target_address}?", abort=True) transaction = ADMINISTRATOR.retarget_proxy( contract_name=contract_name, target_address=target_address, existing_plaintext_secret=existing_secret, new_plaintext_secret=new_secret, just_build_transaction=True) trustee = Trustee(registry=registry, checksum_address=ADMINISTRATOR.deployer_address) data_for_multisig_executives = trustee.produce_data_to_sign( transaction) emitter.message( f"Transaction to retarget {contract_name} proxy to {target_address} was built:", color='green') paint_multisig_proposed_transaction(emitter, data_for_multisig_executives) # TODO: Move this logic to a better place nonce = data_for_multisig_executives['parameters']['nonce'] filepath = f'proposal-{nonce}.json' with open(filepath, 'w') as outfile: json.dump(data_for_multisig_executives, outfile) emitter.echo(f"Saved proposal to {filepath}", color='blue', bold=True) elif retarget: if not target_address: raise click.BadArgumentUsage( message="--target-address is required when using --retarget") if not actor_options.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) else: if not actor_options.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, ignore_deployed=ignore_deployed) emitter.message(f"Successfully deployed and upgraded {contract_name}", color='green') for name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt)
def test_trustee_proposes_multisig_management_operations( testerchain, test_registry): origin = testerchain.etherbase_account tpower = TransactingPower(account=origin, signer=Web3Signer(testerchain.client)) multisig_deployer = MultiSigDeployer(registry=test_registry) threshold = 2 owners = testerchain.unassigned_accounts[0:3] receipts = multisig_deployer.deploy(threshold=threshold, owners=owners, transacting_power=tpower) for step in multisig_deployer.deployment_steps: assert receipts[step]['status'] == 1 multisig_agent = multisig_deployer.make_agent() trustee_address = testerchain.unassigned_accounts[-1] trustee = Trustee(checksum_address=trustee_address, domain=TEMPORARY_DOMAIN, signer=Web3Signer(testerchain.client), registry=test_registry, is_transacting=True) # Propose changing threshold free_payload = { 'nonce': 0, 'from': multisig_agent.contract_address, 'gasPrice': 0 } with patch.object(testerchain, 'build_payload', return_value=free_payload): proposal = trustee.propose_changing_threshold(new_threshold=1) assert proposal.trustee_address == trustee_address assert proposal.target_address == multisig_agent.contract_address assert proposal.nonce == multisig_agent.nonce assert proposal.value == 0 contract_function, params = proposal.decode_transaction_data( registry=test_registry) assert list(params.values()) == [ 1 ] # The new threshold is the only parameter in the call # Propose adding new owner new_owner = testerchain.unassigned_accounts[4] with patch.object(testerchain, 'build_payload', return_value=free_payload): proposal = trustee.propose_adding_owner(new_owner_address=new_owner, evidence=None) assert proposal.trustee_address == trustee_address assert proposal.target_address == multisig_agent.contract_address assert proposal.nonce == multisig_agent.nonce assert proposal.value == 0 contract_function, params = proposal.decode_transaction_data( registry=test_registry) assert list(params.values()) == [ new_owner ] # The new owner is the only parameter in the call # Propose removing owner evicted_owner = testerchain.unassigned_accounts[1] with patch.object(testerchain, 'build_payload', return_value=free_payload): proposal = trustee.propose_removing_owner(evicted_owner) assert proposal.trustee_address == trustee_address assert proposal.target_address == multisig_agent.contract_address assert proposal.nonce == multisig_agent.nonce assert proposal.value == 0 contract_function, params = proposal.decode_transaction_data( registry=test_registry) assert list(params.values()) == [ evicted_owner ] # The owner to remove is the only parameter in the call