示例#1
0
def test_transfer_tokens(click_runner, registry_filepath):
    #
    # Setup
    #

    # Let's transfer some NU to a random stranger
    recipient_address = to_checksum_address(os.urandom(20))

    registry = LocalContractRegistry(filepath=registry_filepath)
    token_agent = NucypherTokenAgent(registry=registry)
    assert token_agent.get_balance(address=recipient_address) == 0

    command = [
        'transfer-tokens', '--target-address', recipient_address, '--value',
        42, '--registry-infile', registry_filepath, '--provider',
        TEST_PROVIDER_URI, '--poa'
    ]

    user_input = '0\n' + 'Y\n' + 'Y\n'
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Check that the NU has arrived to the recipient
    assert token_agent.get_balance(address=recipient_address) == 42
示例#2
0
def test_transfer_tokens(click_runner, registry_filepath,
                         get_random_checksum_address, testerchain):

    # Let's transfer some NU to a random stranger
    recipient_address = get_random_checksum_address()

    registry = LocalContractRegistry(filepath=registry_filepath)
    token_agent = NucypherTokenAgent(registry=registry)
    assert token_agent.get_balance(address=recipient_address) == 0

    command = [
        'transfer-tokens', '--target-address', recipient_address, '--value',
        42, '--registry-infile', registry_filepath, '--provider',
        TEST_PROVIDER_URI
    ]

    user_input = '0\n' + YES_ENTER + YES_ENTER
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Check that the NU has arrived to the recipient
    assert token_agent.get_balance(address=recipient_address) == 42

    # Let's approve an allowance to a random spender
    spender_address = get_random_checksum_address()
    owner_address = testerchain.client.accounts[0]
    assert token_agent.get_allowance(spender=spender_address,
                                     owner=owner_address) == 0

    command = [
        'transfer-tokens', '--target-address', spender_address, '--value', 42,
        '--allowance', '--registry-infile', registry_filepath, '--provider',
        TEST_PROVIDER_URI
    ]

    user_input = '0\n' + YES_ENTER + YES_ENTER
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Check that the NU was approved for the spender
    assert token_agent.get_allowance(spender=spender_address,
                                     owner=owner_address) == 42
示例#3
0
def test_nucypher_deploy_contracts(testerchain, click_runner,
                                   mock_primary_registry_filepath):

    # We start with a blockchain node, and nothing else...
    assert not os.path.isfile(mock_primary_registry_filepath)

    command = (
        'contracts',
        '--registry-outfile',
        mock_primary_registry_filepath,
        '--provider-uri',
        TEST_PROVIDER_URI,
        '--poa',
    )

    user_input = 'Y\n' + f'{INSECURE_DEVELOPMENT_PASSWORD}\n' * 6
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Check that the primary contract registry was written
    assert os.path.isfile(mock_primary_registry_filepath)

    # Now show that we can use contract Agency and read from the blockchain
    token_agent = NucypherTokenAgent()
    assert token_agent.get_balance() == 0
    miner_agent = MinerAgent()
    assert miner_agent.get_current_period()
    testerchain.sever_connection()
def test_nucypher_deploy_contracts(testerchain, click_runner,
                                   mock_primary_registry_filepath):

    # We start with a blockchain node, and nothing else...
    assert not os.path.isfile(mock_primary_registry_filepath)

    command = ('contracts', '--registry-outfile',
               mock_primary_registry_filepath, '--provider-uri',
               TEST_PROVIDER_URI, '--poa')

    user_input = 'Y\n' + f'{INSECURE_DEVELOPMENT_PASSWORD}\n' * 8
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Ensure there is a report on each contract
    for registry_name in Deployer.contract_names:
        assert registry_name in result.output

    # Check that the primary contract registry was written
    # and peek at some of the registered entries
    assert os.path.isfile(mock_primary_registry_filepath)
    with open(mock_primary_registry_filepath, 'r') as file:

        # Ensure every contract's name was written to the file, somehow
        raw_registry_data = file.read()
        for registry_name in Deployer.contract_names:
            assert registry_name in raw_registry_data

        # Ensure the Registry is JSON deserializable
        registry_data = json.loads(raw_registry_data)

        # and that is has the correct number of entries
        assert len(registry_data) == 9

        # Read several records
        token_record, escrow_record, dispatcher_record, *other_records = registry_data
        registered_name, registered_address, registered_abi = token_record
        token_agent = NucypherTokenAgent()
        assert token_agent.contract_name == registered_name
        assert token_agent.registry_contract_name == registered_name
        assert token_agent.contract_address == registered_address

    # Now show that we can use contract Agency and read from the blockchain
    assert token_agent.get_balance() == 0
    miner_agent = MinerAgent()
    assert miner_agent.get_current_period()

    # and at least the others can be instantiated
    assert PolicyAgent()
    assert MiningAdjudicatorAgent()
    testerchain.sever_connection()
示例#5
0
class NucypherTokenActor:
    """
    Concrete base class for any actor that will interface with NuCypher's ethereum smart contracts.
    """
    class ActorError(Exception):
        pass

    def __init__(self,
                 checksum_address: str = None,
                 blockchain: Blockchain = None) -> None:
        """
        :param checksum_address:  If not passed, we assume this is an unknown actor

        :param token_agent:  The token agent with the blockchain attached; If not passed, A default
        token agent and blockchain connection will be created from default values.

        """
        try:
            parent_address = self.checksum_public_address  # type: str
            if checksum_address is not None:
                if parent_address != checksum_address:
                    raise ValueError("Can't have two different addresses.")
        except AttributeError:
            self.checksum_public_address = checksum_address  # type: str

        if blockchain is None:
            blockchain = Blockchain.connect()
        self.blockchain = blockchain

        self.token_agent = NucypherTokenAgent()
        self._transaction_cache = list(
        )  # type: list # track transactions transmitted

    def __repr__(self):
        class_name = self.__class__.__name__
        r = "{}(address='{}')"
        r = r.format(class_name, self.checksum_public_address)
        return r

    @property
    def eth_balance(self):
        """Return this actors's current ETH balance"""
        balance = self.token_agent.blockchain.interface.w3.eth.getBalance(
            self.checksum_public_address)
        return balance

    @property
    def token_balance(self):
        """Return this actors's current token balance"""
        balance = self.token_agent.get_balance(
            address=self.checksum_public_address)
        return balance
示例#6
0
def test_transfer_tokens(click_runner, mock_primary_registry_filepath):
    #
    # Setup
    #

    # Simulate "Reconnection"
    real_attach_provider = BlockchainDeployerInterface._attach_provider
    cached_blockchain = BlockchainDeployerInterface.reconnect()
    registry = cached_blockchain.registry
    assert registry.filepath == mock_primary_registry_filepath

    def attach_cached_provider(interface, *args, **kwargs):
        cached_provider = cached_blockchain.provider
        real_attach_provider(interface, provider=cached_provider)

    BlockchainDeployerInterface._attach_provider = attach_cached_provider

    # Let's transfer some NU to a random stranger
    recipient_address = to_checksum_address(os.urandom(20))

    token_agent = NucypherTokenAgent()
    assert token_agent.get_balance(address=recipient_address) == 0

    command = [
        'transfer', '--recipient-address', recipient_address, '--amount', 42,
        '--registry-infile', mock_primary_registry_filepath, '--provider',
        TEST_PROVIDER_URI, '--poa'
    ]

    user_input = '0\n' + 'Y\n' + 'Y\n'
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Check that the NU has arrived to the recipient
    assert token_agent.get_balance(address=recipient_address) == 42
示例#7
0
class NucypherTokenActor:
    """
    Concrete base class for any actor that will interface with NuCypher's ethereum smart contracts.
    """
    class ActorError(Exception):
        pass

    def __init__(self,
                 blockchain: BlockchainInterface,
                 checksum_address: str = None):
        """
        :param checksum_address:  If not passed, we assume this is an unknown actor
        """
        try:
            parent_address = self.checksum_address  # type: str
            if checksum_address is not None:
                if parent_address != checksum_address:
                    raise ValueError("Can't have two different addresses.")
        except AttributeError:
            self.checksum_address = checksum_address  # type: str

        self.blockchain = blockchain
        self.token_agent = NucypherTokenAgent(blockchain=self.blockchain)
        self._saved_receipts = list(
        )  # type: list # track receipts of transmitted transactions

    def __repr__(self):
        class_name = self.__class__.__name__
        r = "{}(address='{}')"
        r = r.format(class_name, self.checksum_address)
        return r

    def __eq__(self, other) -> bool:
        """Actors are equal if they have the same address."""
        return bool(self.checksum_address == other.checksum_address)

    @property
    def eth_balance(self) -> Decimal:
        """Return this actors's current ETH balance"""
        balance = self.blockchain.client.get_balance(self.checksum_address)
        return self.blockchain.client.w3.fromWei(balance, 'ether')

    @property
    def token_balance(self) -> NU:
        """Return this actors's current token balance"""
        balance = int(
            self.token_agent.get_balance(address=self.checksum_address))
        nu_balance = NU(balance, 'NuNit')
        return nu_balance
示例#8
0
class NucypherTokenActor:
    """
    Concrete base class for any actor that will interface with NuCypher's ethereum smart contracts.
    """
    class ActorError(Exception):
        pass

    def __init__(self,
                 checksum_address: str = None,
                 blockchain: Blockchain = None):
        """
        :param checksum_address:  If not passed, we assume this is an unknown actor
        """
        try:
            parent_address = self.checksum_address  # type: str
            if checksum_address is not None:
                if parent_address != checksum_address:
                    raise ValueError("Can't have two different addresses.")
        except AttributeError:
            self.checksum_address = checksum_address  # type: str

        if blockchain is None:
            blockchain = Blockchain.connect()  # Attempt to connect
        self.blockchain = blockchain

        self.token_agent = NucypherTokenAgent(blockchain=self.blockchain)
        self._transaction_cache = list(
        )  # type: list # track transactions transmitted

    def __repr__(self):
        class_name = self.__class__.__name__
        r = "{}(address='{}')"
        r = r.format(class_name, self.checksum_address)
        return r

    @property
    def eth_balance(self) -> Decimal:
        """Return this actors's current ETH balance"""
        balance = self.blockchain.interface.get_balance(self.checksum_address)
        return self.blockchain.interface.fromWei(balance, 'ether')

    @property
    def token_balance(self) -> NU:
        """Return this actors's current token balance"""
        balance = int(
            self.token_agent.get_balance(address=self.checksum_address))
        nu_balance = NU(balance, 'NuNit')
        return nu_balance
示例#9
0
class MinerEscrowDeployer(ContractDeployer):
    """
    Deploys the MinerEscrow ethereum contract to the blockchain.  Depends on NucypherTokenAgent
    """

    agency = MinerAgent
    contract_name = agency.registry_contract_name
    _upgradeable = True
    __proxy_deployer = DispatcherDeployer

    def __init__(self, economics: TokenEconomics = None, *args, **kwargs):

        super().__init__(*args, **kwargs)
        self.token_agent = NucypherTokenAgent(blockchain=self.blockchain)
        if not economics:
            economics = TokenEconomics()
        self.__economics = economics

    def __check_policy_manager(self):
        result = self.contract.functions.policyManager().call()
        if result is self.blockchain.NULL_ADDRESS:
            raise RuntimeError("PolicyManager contract is not initialized.")

    def deploy(self, secret_hash: bytes, gas_limit: int = None) -> dict:
        """
        Deploy and publish the MinersEscrow contract
        to the blockchain network specified in self.blockchain.network.

        Deployment can only ever be executed exactly once!

        Emits the following blockchain network transactions:
            - MinerEscrow contract deployment
            - MinerEscrow dispatcher deployment
            - Transfer reward tokens origin -> MinerEscrow contract
            - MinerEscrow contract initialization

        Returns transaction hashes in a dict.
        """

        # Raise if not all-systems-go
        self.check_deployment_readiness()

        # Build deployment arguments
        origin_args = {
            'from': self.deployer_address,
            'gasPrice': self.blockchain.interface.w3.eth.gasPrice
        }
        if gas_limit:
            origin_args.update({'gas': gas_limit})

        # 1 - Deploy #
        the_escrow_contract, deploy_txhash, = \
            self.blockchain.interface.deploy_contract(self.contract_name,
                                                      self.token_agent.contract_address,
                                                      *self.__economics.staking_deployment_parameters)

        # 2 - Deploy the dispatcher used for updating this contract #
        dispatcher_deployer = DispatcherDeployer(
            blockchain=self.blockchain,
            target_contract=the_escrow_contract,
            deployer_address=self.deployer_address)

        dispatcher_deploy_txhashes = dispatcher_deployer.deploy(
            secret_hash=secret_hash, gas_limit=gas_limit)

        # Cache the dispatcher contract
        dispatcher_contract = dispatcher_deployer.contract
        self.__dispatcher_contract = dispatcher_contract

        # Wrap the escrow contract
        wrapped_escrow_contract = self.blockchain.interface._wrap_contract(
            dispatcher_contract, target_contract=the_escrow_contract)

        # Switch the contract for the wrapped one
        the_escrow_contract = wrapped_escrow_contract

        # 3 - Transfer tokens to the miner escrow #
        reward_txhash = self.token_agent.contract.functions.transfer(
            the_escrow_contract.address,
            self.__economics.erc20_reward_supply).transact(origin_args)

        _reward_receipt = self.blockchain.wait_for_receipt(reward_txhash)
        escrow_balance = self.token_agent.get_balance(
            address=the_escrow_contract.address)

        # 4 - Initialize the Miner Escrow contract
        init_txhash = the_escrow_contract.functions.initialize().transact(
            origin_args)
        _init_receipt = self.blockchain.wait_for_receipt(init_txhash)

        # Gather the transaction hashes
        deployment_transactions = {
            'deploy': deploy_txhash,
            'dispatcher_deploy': dispatcher_deploy_txhashes['txhash'],
            'reward_transfer': reward_txhash,
            'initialize': init_txhash
        }

        # Set the contract and transaction hashes #
        self._contract = the_escrow_contract
        self.deployment_transactions = deployment_transactions
        return deployment_transactions

    def upgrade(self, existing_secret_plaintext: bytes,
                new_secret_hash: bytes):

        # Raise if not all-systems-go
        self.check_deployment_readiness()
        origin_args = {
            'from': self.deployer_address,
            'gas': 5000000
        }  # TODO: Gas management

        existing_bare_contract = self.blockchain.interface.get_contract_by_name(
            name=self.contract_name,
            proxy_name=self.__proxy_deployer.contract_name,
            use_proxy_address=False)
        dispatcher_deployer = DispatcherDeployer(
            blockchain=self.blockchain,
            target_contract=existing_bare_contract,
            deployer_address=self.deployer_address,
            bare=True)  # acquire agency for the dispatcher itself.

        # 2 - Deploy new version #
        the_escrow_contract, deploy_txhash = self.blockchain.interface.deploy_contract(
            self.contract_name, self.token_agent.contract_address,
            *self.__economics.staking_deployment_parameters)

        # 5 - Wrap the escrow contract
        wrapped_escrow_contract = self.blockchain.interface._wrap_contract(
            wrapper_contract=dispatcher_deployer.contract,
            target_contract=the_escrow_contract)
        self._contract = wrapped_escrow_contract

        # 4 - Set the new Dispatcher target
        upgrade_tx_hash = dispatcher_deployer.retarget(
            new_target=the_escrow_contract.address,
            existing_secret_plaintext=existing_secret_plaintext,
            new_secret_hash=new_secret_hash)
        _upgrade_receipt = self.blockchain.wait_for_receipt(upgrade_tx_hash)

        # Respond
        upgrade_transaction = {
            'deploy': deploy_txhash,
            'retarget': upgrade_tx_hash
        }
        return upgrade_transaction

    def rollback(self, existing_secret_plaintext: bytes,
                 new_secret_hash: bytes):
        existing_bare_contract = self.blockchain.interface.get_contract_by_name(
            name=self.contract_name,
            proxy_name=self.__proxy_deployer.contract_name,
            use_proxy_address=False)
        dispatcher_deployer = DispatcherDeployer(
            blockchain=self.blockchain,
            target_contract=existing_bare_contract,
            deployer_address=self.deployer_address,
            bare=True)  # acquire agency for the dispatcher itself.

        rollback_txhash = dispatcher_deployer.rollback(
            existing_secret_plaintext=existing_secret_plaintext,
            new_secret_hash=new_secret_hash)

        _rollback_receipt = self.blockchain.wait_for_receipt(
            txhash=rollback_txhash)
        return rollback_txhash

    def make_agent(self) -> EthereumContractAgent:
        self.__check_policy_manager(
        )  # Ensure the PolicyManager contract has already been initialized
        agent = self.agency(blockchain=self.blockchain,
                            contract=self._contract)
        return agent
示例#10
0
def test_nucypher_deploy_contracts(click_runner, mock_allocation_infile,
                                   token_economics, registry_filepath):

    #
    # Main
    #

    command = [
        'contracts', '--registry-outfile', registry_filepath, '--provider',
        TEST_PROVIDER_URI, '--poa'
    ]

    user_input = '0\n' + 'Y\n' + (f'{INSECURE_SECRETS[1]}\n' * 8) + 'DEPLOY'
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Ensure there is a report on each contract
    contract_names = tuple(a.registry_contract_name
                           for a in EthereumContractAgent.__subclasses__())
    for registry_name in contract_names:
        assert registry_name in result.output

    # Check that the primary contract registry was written
    # and peek at some of the registered entries
    assert os.path.isfile(registry_filepath)
    with open(registry_filepath, 'r') as file:

        # Ensure every contract's name was written to the file, somehow
        raw_registry_data = file.read()
        for registry_name in contract_names:
            assert registry_name in raw_registry_data

        # Ensure the Registry is JSON deserializable
        registry_data = json.loads(raw_registry_data)

        # and that is has the correct number of entries
        assert len(registry_data) == 9

        # Read several records
        token_record, escrow_record, dispatcher_record, *other_records = registry_data
        registered_name, registered_address, registered_abi = token_record

    #
    # Agency
    #
    registry = LocalContractRegistry(filepath=registry_filepath)

    token_agent = NucypherTokenAgent(registry=registry)
    assert token_agent.contract_name == registered_name
    assert token_agent.registry_contract_name == registered_name
    assert token_agent.contract_address == registered_address

    # Now show that we can use contract Agency and read from the blockchain
    assert token_agent.get_balance() == 0
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=registry)
    assert staking_agent.get_current_period()

    # and at least the others can be instantiated
    assert PolicyManagerAgent(registry=registry)

    # This agent wasn't instantiated before, so we have to supply the blockchain
    blockchain = staking_agent.blockchain
    assert AdjudicatorAgent(registry=registry)
示例#11
0
class StakingEscrowDeployer(ContractDeployer):
    """
    Deploys the StakingEscrow ethereum contract to the blockchain.  Depends on NucypherTokenAgent
    """

    agency = StakingEscrowAgent
    contract_name = agency.registry_contract_name
    number_of_deployment_transactions = 4
    _upgradeable = True
    __proxy_deployer = DispatcherDeployer

    def __init__(self, economics: TokenEconomics = None, *args, **kwargs):

        super().__init__(*args, **kwargs)
        self.token_agent = NucypherTokenAgent(blockchain=self.blockchain)
        if not economics:
            economics = TokenEconomics()
        self.__economics = economics
        self.__dispatcher_contract = None

    def __check_policy_manager(self):
        result = self.contract.functions.policyManager().call()
        if result == self.blockchain.NULL_ADDRESS:
            raise RuntimeError("PolicyManager contract is not initialized.")

    def _deploy_essential(self, gas_limit: int = None):
        escrow_constructor_args = (
            self.token_agent.contract_address,
            *self.__economics.staking_deployment_parameters)
        the_escrow_contract, deploy_receipt = self.blockchain.deploy_contract(
            self.contract_name, *escrow_constructor_args, gas_limit=gas_limit)
        return the_escrow_contract, deploy_receipt

    def deploy(self,
               secret_hash: bytes,
               gas_limit: int = None,
               progress=None) -> dict:
        """
        Deploy and publish the StakingEscrow contract
        to the blockchain network specified in self.blockchain.network.

        Deployment can only ever be executed exactly once!

        Emits the following blockchain network transactions:
            - StakingEscrow contract deployment
            - StakingEscrow dispatcher deployment
            - Transfer reward tokens origin -> StakingEscrow contract
            - StakingEscrow contract initialization

        Returns transaction hashes in a dict.
        """

        # Raise if not all-systems-go
        self.check_deployment_readiness()

        # Build deployment arguments
        origin_args = {}
        if gas_limit:
            origin_args.update({'gas': gas_limit})

        # 1 - Deploy #
        the_escrow_contract, deploy_receipt = self._deploy_essential(
            gas_limit=gas_limit)
        if progress:
            progress.update(1)

        # 2 - Deploy the dispatcher used for updating this contract #
        dispatcher_deployer = DispatcherDeployer(
            blockchain=self.blockchain,
            target_contract=the_escrow_contract,
            deployer_address=self.deployer_address)

        dispatcher_deploy_receipt = dispatcher_deployer.deploy(
            secret_hash=secret_hash, gas_limit=gas_limit)
        if progress:
            progress.update(1)

        # Cache the dispatcher contract
        dispatcher_contract = dispatcher_deployer.contract
        self.__dispatcher_contract = dispatcher_contract

        # Wrap the escrow contract
        wrapped_escrow_contract = self.blockchain._wrap_contract(
            dispatcher_contract, target_contract=the_escrow_contract)

        # Switch the contract for the wrapped one
        the_escrow_contract = wrapped_escrow_contract

        # 3 - Transfer the reward supply tokens to StakingEscrow #
        reward_function = self.token_agent.contract.functions.transfer(
            the_escrow_contract.address, self.__economics.erc20_reward_supply)

        reward_receipt = self.blockchain.send_transaction(
            contract_function=reward_function,
            sender_address=self.deployer_address,
            payload=origin_args)
        if progress:
            progress.update(1)

        # Make a call.
        _escrow_balance = self.token_agent.get_balance(
            address=the_escrow_contract.address)

        # 4 - Initialize the StakingEscrow contract
        init_function = the_escrow_contract.functions.initialize()

        init_receipt = self.blockchain.send_transaction(
            contract_function=init_function,
            sender_address=self.deployer_address,
            payload=origin_args)
        if progress:
            progress.update(1)

        # Gather the transaction hashes
        deployment_receipts = {
            'deploy': deploy_receipt,
            'dispatcher_deploy': dispatcher_deploy_receipt['deployment'],
            'reward_transfer': reward_receipt,
            'initialize': init_receipt
        }

        # Set the contract and transaction hashes #
        self._contract = the_escrow_contract
        self.deployment_receipts = deployment_receipts
        return deployment_receipts

    def upgrade(self,
                existing_secret_plaintext: bytes,
                new_secret_hash: bytes,
                gas_limit: int = None):

        # 1 - Raise if not all-systems-go #
        # TODO: Fails when this same object was used previously to deploy
        self.check_deployment_readiness()

        existing_bare_contract = self.blockchain.get_contract_by_name(
            name=self.contract_name,
            proxy_name=self.__proxy_deployer.contract_name,
            use_proxy_address=False)
        dispatcher_deployer = DispatcherDeployer(
            blockchain=self.blockchain,
            target_contract=existing_bare_contract,
            deployer_address=self.deployer_address,
            bare=True)  # acquire agency for the dispatcher itself.

        # 2 - Deploy new version #
        new_escrow_contract, deploy_receipt = self._deploy_essential(
            gas_limit=gas_limit)

        # 3 - Wrap the escrow contract #
        wrapped_escrow_contract = self.blockchain._wrap_contract(
            wrapper_contract=dispatcher_deployer.contract,
            target_contract=new_escrow_contract)

        # 4 - Set the new Dispatcher target #
        upgrade_receipt = dispatcher_deployer.retarget(
            new_target=new_escrow_contract.address,
            existing_secret_plaintext=existing_secret_plaintext,
            new_secret_hash=new_secret_hash,
            gas_limit=gas_limit)

        # Respond
        upgrade_transaction = {
            'deploy': deploy_receipt,
            'retarget': upgrade_receipt
        }
        # Switch the contract for the wrapped one
        self._contract = wrapped_escrow_contract
        return upgrade_transaction

    def rollback(self,
                 existing_secret_plaintext: bytes,
                 new_secret_hash: bytes,
                 gas_limit: int = None):
        existing_bare_contract = self.blockchain.get_contract_by_name(
            name=self.contract_name,
            proxy_name=self.__proxy_deployer.contract_name,
            use_proxy_address=False)
        dispatcher_deployer = DispatcherDeployer(
            blockchain=self.blockchain,
            target_contract=existing_bare_contract,
            deployer_address=self.deployer_address,
            bare=True)  # acquire agency for the dispatcher itself.

        rollback_receipt = dispatcher_deployer.rollback(
            existing_secret_plaintext=existing_secret_plaintext,
            new_secret_hash=new_secret_hash,
            gas_limit=gas_limit)

        return rollback_receipt

    def make_agent(self) -> EthereumContractAgent:
        #self.__check_policy_manager()  # Ensure the PolicyManager contract has already been initialized
        agent = self.agency(blockchain=self.blockchain,
                            contract=self._contract)
        return agent
示例#12
0
def test_nucypher_deploy_contracts(click_runner, token_economics,
                                   registry_filepath, testerchain):

    #
    # Main
    #

    assert not os.path.exists(
        registry_filepath), f"Registry File '{registry_filepath}' Exists."
    assert not os.path.lexists(
        registry_filepath), f"Registry File '{registry_filepath}' Exists."

    command = [
        'contracts', '--registry-outfile', registry_filepath, '--provider',
        TEST_PROVIDER_URI, '--se-test-mode'
    ]

    user_input = '0\n' + 'Y\n' + 'DEPLOY'
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Ensure there is a report on each primary contract
    contract_names = tuple(
        a.contract_name
        for a in ContractAdministrator.primary_deployer_classes)
    for registry_name in contract_names:
        assert registry_name in result.output

    # Check that the primary contract registry was written
    # and peek at some of the registered entries
    assert os.path.isfile(registry_filepath)
    with open(registry_filepath, 'r') as file:

        # Ensure every contract's name was written to the file, somehow
        raw_registry_data = file.read()
        for registry_name in contract_names:
            assert registry_name in raw_registry_data

        # Ensure the Registry is JSON deserializable
        registry_data = json.loads(raw_registry_data)

        # and that is has the correct number of entries
        assert len(registry_data) == 9

        # Read several records
        token_record, escrow_record, dispatcher_record, *other_records = registry_data
        registered_name, registered_version, registered_address, registered_abi = token_record

    #
    # Agency
    #
    registry = LocalContractRegistry(filepath=registry_filepath)

    token_agent = NucypherTokenAgent(registry=registry)
    assert token_agent.contract_name == registered_name
    assert token_agent.registry_contract_name == registered_name
    assert token_agent.contract_address == registered_address
    assert token_agent.contract.version == registered_version

    # Now show that we can use contract Agency and read from the blockchain
    assert token_agent.get_balance() == 0
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=registry)
    assert staking_agent.get_current_period()
    assert staking_agent.contract.functions.isTestContract().call()

    # and at least the others can be instantiated
    assert PolicyManagerAgent(registry=registry)
    assert AdjudicatorAgent(registry=registry)
示例#13
0
def select_client_account(emitter,
                          provider_uri: str,
                          prompt: str = None,
                          default: int = 0,
                          registry=None,
                          show_balances: bool = True,
                          show_staking: bool = False,
                          network: str = None,
                          poa: bool = False
                          ) -> str:
    """
    Note: Setting show_balances to True, causes an eager contract and blockchain connection.
    """
    # TODO: Break show_balances into show_eth_balance and show_token_balance

    if not provider_uri:
        raise ValueError("Provider URI must be provided to select a wallet account.")

    # Lazy connect the blockchain interface
    if not BlockchainInterfaceFactory.is_interface_initialized(provider_uri=provider_uri):
        BlockchainInterfaceFactory.initialize_interface(provider_uri=provider_uri, poa=poa, emitter=emitter)
    blockchain = BlockchainInterfaceFactory.get_interface(provider_uri=provider_uri)

    # Lazy connect to contracts
    token_agent = None
    if show_balances or show_staking:
        if not registry:
            registry = InMemoryContractRegistry.from_latest_publication(network=network)
        token_agent = NucypherTokenAgent(registry=registry)

    # Real wallet accounts
    enumerated_accounts = dict(enumerate(blockchain.client.accounts))
    if len(enumerated_accounts) < 1:
        emitter.echo("No ETH accounts were found.", color='red', bold=True)
        raise click.Abort()

    # Display account info
    headers = ['Account']
    if show_staking:
        headers.append('Staking')
    if show_balances:
        headers.extend(('', ''))

    rows = list()
    for index, account in enumerated_accounts.items():
        row = [account]
        if show_staking:
            staker = Staker(is_me=True, checksum_address=account, registry=registry)
            staker.stakes.refresh()
            is_staking = 'Yes' if bool(staker.stakes) else 'No'
            row.append(is_staking)
        if show_balances:
            token_balance = NU.from_nunits(token_agent.get_balance(address=account))
            ether_balance = Web3.fromWei(blockchain.client.get_balance(account=account), 'ether')
            row.extend((token_balance, f'{ether_balance} ETH'))
        rows.append(row)
    emitter.echo(tabulate(rows, headers=headers, showindex='always'))

    # Prompt the user for selection, and return
    prompt = prompt or "Select index of account"
    account_range = click.IntRange(min=0, max=len(enumerated_accounts)-1)
    choice = click.prompt(prompt, type=account_range, default=default)
    chosen_account = enumerated_accounts[choice]

    emitter.echo(f"Selected {choice}: {chosen_account}", color='blue')
    return chosen_account
示例#14
0
def test_deploy_idle_network(testerchain, deployment_progress, test_registry):
    origin, *everybody_else = testerchain.client.accounts

    #
    # Nucypher Token
    #
    token_deployer = NucypherTokenDeployer(registry=test_registry,
                                           deployer_address=origin)
    assert token_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert token_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not token_deployer.is_deployed()

    token_deployer.deploy(progress=deployment_progress)
    assert token_deployer.is_deployed()

    token_agent = NucypherTokenAgent(registry=test_registry)
    assert token_agent.contract_address == token_deployer.contract_address

    another_token_agent = token_deployer.make_agent()
    assert another_token_agent.contract_address == token_deployer.contract_address == token_agent.contract_address

    #
    # StakingEscrow - in INIT mode, i.e. stub for StakingEscrow
    #
    staking_escrow_deployer = StakingEscrowDeployer(registry=test_registry,
                                                    deployer_address=origin)
    assert staking_escrow_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert staking_escrow_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not staking_escrow_deployer.is_deployed()

    staking_escrow_deployer.deploy(progress=deployment_progress,
                                   deployment_mode=constants.INIT)
    assert not staking_escrow_deployer.is_deployed()

    #
    # Policy Manager
    #
    policy_manager_deployer = PolicyManagerDeployer(registry=test_registry,
                                                    deployer_address=origin)

    assert policy_manager_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert policy_manager_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not policy_manager_deployer.is_deployed()

    policy_manager_deployer.deploy(progress=deployment_progress)
    assert policy_manager_deployer.is_deployed()

    policy_agent = policy_manager_deployer.make_agent()
    assert policy_agent.contract_address == policy_manager_deployer.contract_address

    #
    # Adjudicator
    #
    adjudicator_deployer = AdjudicatorDeployer(registry=test_registry,
                                               deployer_address=origin)

    assert adjudicator_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert adjudicator_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not adjudicator_deployer.is_deployed()

    adjudicator_deployer.deploy(progress=deployment_progress)
    assert adjudicator_deployer.is_deployed()

    adjudicator_agent = adjudicator_deployer.make_agent()
    assert adjudicator_agent.contract_address == adjudicator_deployer.contract_address

    #
    # StakingEscrow - in IDLE mode, i.e. without activation steps (approve_funding and initialize)
    #
    staking_escrow_deployer = StakingEscrowDeployer(registry=test_registry,
                                                    deployer_address=origin)
    assert staking_escrow_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert staking_escrow_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not staking_escrow_deployer.is_deployed()

    staking_escrow_deployer.deploy(progress=deployment_progress,
                                   deployment_mode=constants.IDLE)
    assert staking_escrow_deployer.is_deployed()

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=test_registry)
    assert staking_agent.contract_address == staking_escrow_deployer.contract_address

    # The contract has no tokens yet
    assert token_agent.get_balance(staking_agent.contract_address) == 0
示例#15
0
class StakeHolder(BaseConfiguration):

    _NAME = 'stakeholder'
    TRANSACTION_GAS = {}

    class NoFundingAccount(BaseConfiguration.ConfigurationError):
        pass

    class NoStakes(BaseConfiguration.ConfigurationError):
        pass

    def __init__(self,
                 blockchain: BlockchainInterface,
                 sync_now: bool = True,
                 *args,
                 **kwargs):

        super().__init__(*args, **kwargs)

        self.log = Logger(f"stakeholder")

        # Blockchain and Contract connection
        self.blockchain = blockchain
        self.staking_agent = StakingEscrowAgent(blockchain=blockchain)
        self.token_agent = NucypherTokenAgent(blockchain=blockchain)
        self.economics = TokenEconomics()

        # Mode
        self.connect(blockchain=blockchain)

        self.__accounts = list()
        self.__stakers = dict()
        self.__transacting_powers = dict()

        self.__get_accounts()

        if sync_now:
            self.read_onchain_stakes()  # Stakes

    #
    # Configuration
    #

    def static_payload(self) -> dict:
        """Values to read/write from stakeholder JSON configuration files"""
        payload = dict(provider_uri=self.blockchain.provider_uri,
                       blockchain=self.blockchain.to_dict(),
                       accounts=self.__accounts,
                       stakers=self.__serialize_stakers())
        return payload

    @classmethod
    def from_configuration_file(cls,
                                filepath: str = None,
                                sync_now: bool = True,
                                **overrides) -> 'StakeHolder':
        filepath = filepath or cls.default_filepath()
        payload = cls._read_configuration_file(filepath=filepath)

        # Sub config
        blockchain_payload = payload.pop('blockchain')
        blockchain = BlockchainInterface.from_dict(payload=blockchain_payload)
        blockchain.connect(sync_now=sync_now)  # TODO: Leave this here?

        payload.update(dict(blockchain=blockchain))

        payload.update(overrides)
        instance = cls(filepath=filepath, **payload)
        return instance

    @validate_checksum_address
    def attach_transacting_power(self,
                                 checksum_address: str,
                                 password: str = None) -> None:
        try:
            transacting_power = self.__transacting_powers[checksum_address]
        except KeyError:
            transacting_power = TransactingPower(blockchain=self.blockchain,
                                                 password=password,
                                                 account=checksum_address)
            self.__transacting_powers[checksum_address] = transacting_power
        transacting_power.activate(password=password)

    def to_configuration_file(self, *args, **kwargs) -> str:
        filepath = super().to_configuration_file(*args, **kwargs)
        return filepath

    def connect(self, blockchain: BlockchainInterface = None) -> None:
        """Go Online"""
        if not self.staking_agent:
            self.staking_agent = StakingEscrowAgent(blockchain=blockchain)
        if not self.token_agent:
            self.token_agent = NucypherTokenAgent(blockchain=blockchain)
        self.blockchain = self.token_agent.blockchain

    #
    # Account Utilities
    #

    @property
    def accounts(self) -> list:
        return self.__accounts

    def __get_accounts(self) -> None:
        accounts = self.blockchain.client.accounts
        self.__accounts.extend(accounts)

    #
    # Staking Utilities
    #

    def read_onchain_stakes(self, account: str = None) -> None:
        if account:
            accounts = [account]
        else:
            accounts = self.__accounts

        for account in accounts:
            stakes = list(
                self.staking_agent.get_all_stakes(staker_address=account))
            if stakes:
                staker = Staker(is_me=True,
                                checksum_address=account,
                                blockchain=self.blockchain)
                self.__stakers[account] = staker

    @property
    def total_stake(self) -> NU:
        total = sum(staker.locked_tokens() for staker in self.stakers)
        return total

    @property
    def stakers(self) -> List[Staker]:
        return list(self.__stakers.values())

    @property
    def stakes(self) -> list:
        payload = list()
        for staker in self.__stakers.values():
            payload.extend(staker.stakes)
        return payload

    @property
    def account_balances(self) -> dict:
        balances = dict()
        for account in self.__accounts:
            funds = {
                'ETH': self.blockchain.client.get_balance(account),
                'NU': self.token_agent.get_balance(account)
            }
            balances.update({account: funds})
        return balances

    @property
    def staker_balances(self) -> dict:
        balances = dict()
        for staker in self.stakers:
            staker_funds = {
                'ETH': staker.eth_balance,
                'NU': staker.token_balance
            }
            balances[staker.checksum_address] = {
                staker.checksum_address: staker_funds
            }
        return balances

    def __serialize_stakers(self) -> list:
        payload = list()
        for staker in self.stakers:
            payload.append(staker.to_dict())
        return payload

    def get_active_staker(self, address: str) -> Staker:
        self.read_onchain_stakes(account=address)
        try:
            return self.__stakers[address]
        except KeyError:
            raise self.NoStakes(f"{address} does not have any stakes.")

    def create_worker_configuration(self, staking_address: str,
                                    worker_address: str, password: str,
                                    **configuration):
        """Generates a worker JSON configuration file for a given staking address."""
        from nucypher.config.characters import UrsulaConfiguration
        worker_configuration = UrsulaConfiguration.generate(
            checksum_address=staking_address,
            worker_address=worker_address,
            password=password,
            config_root=self.config_root,
            federated_only=False,
            provider_uri=self.blockchain.provider_uri,
            **configuration)
        return worker_configuration

    #
    # Actions
    #

    def set_worker(self,
                   staker_address: str,
                   worker_address: str,
                   password: str = None):
        self.attach_transacting_power(checksum_address=staker_address,
                                      password=password)
        staker = self.get_active_staker(address=staker_address)
        receipt = self.staking_agent.set_worker(
            staker_address=staker.checksum_address,
            worker_address=worker_address)

        self.to_configuration_file(override=True)
        return receipt

    def initialize_stake(
        self,
        amount: NU,
        duration: int,
        checksum_address: str,
        password: str = None,
    ) -> Stake:

        # Existing Staker address
        if not is_checksum_address(checksum_address):
            raise ValueError(
                f"{checksum_address} is an invalid EIP-55 checksum address.")

        try:
            staker = self.__stakers[checksum_address]
        except KeyError:
            if checksum_address not in self.__accounts:
                raise ValueError(
                    f"{checksum_address} is an unknown wallet address.")
            else:
                staker = Staker(is_me=True,
                                checksum_address=checksum_address,
                                blockchain=self.blockchain)

        # Don the transacting power for the staker's account.
        self.attach_transacting_power(checksum_address=staker.checksum_address,
                                      password=password)
        new_stake = staker.initialize_stake(amount=amount,
                                            lock_periods=duration)

        # Update local cache and save to disk.
        self.__stakers[checksum_address] = staker
        staker.stake_tracker.refresh(
            checksum_addresses=[staker.checksum_address])
        self.to_configuration_file(override=True)

        return new_stake

    def divide_stake(
        self,
        address: str,
        index: int,
        value: NU,
        duration: int,
        password: str = None,
    ):

        staker = self.get_active_staker(address=address)
        if not staker.is_staking:
            raise Stake.StakingError(
                f"{staker.checksum_address} has no published stakes.")

        self.attach_transacting_power(checksum_address=staker.checksum_address,
                                      password=password)
        result = staker.divide_stake(stake_index=index,
                                     additional_periods=duration,
                                     target_value=value)

        # Save results to disk
        self.to_configuration_file(override=True)
        return result

    def calculate_rewards(self) -> dict:
        rewards = dict()
        for staker in self.stakers:
            reward = staker.calculate_reward()
            rewards[staker.checksum_address] = reward
        return rewards

    def collect_rewards(self,
                        staker_address: str,
                        password: str = None,
                        withdraw_address: str = None,
                        staking: bool = True,
                        policy: bool = True) -> Dict[str, dict]:

        if not staking and not policy:
            raise ValueError(
                "Either staking or policy must be True in order to collect rewards"
            )

        try:
            staker = self.get_active_staker(address=staker_address)
        except self.NoStakes:
            staker = Staker(is_me=True,
                            checksum_address=staker_address,
                            blockchain=self.blockchain)

        self.attach_transacting_power(checksum_address=staker.checksum_address,
                                      password=password)

        receipts = dict()
        if staking:
            receipts['staking_reward'] = staker.collect_staking_reward()
        if policy:
            receipts['policy_reward'] = staker.collect_policy_reward(
                collector_address=withdraw_address)

        self.to_configuration_file(override=True)
        return receipts
示例#16
0
def test_nucypher_deploy_contracts(click_runner,
                                   mock_primary_registry_filepath,
                                   mock_allocation_infile, token_economics):

    Agency.clear()

    #
    # Setup
    #

    # We start with a blockchain node, and nothing else...
    if os.path.isfile(mock_primary_registry_filepath):
        os.remove(mock_primary_registry_filepath)
    assert not os.path.isfile(mock_primary_registry_filepath)

    #
    # Main
    #

    command = [
        'contracts', '--registry-outfile', mock_primary_registry_filepath,
        '--provider-uri', TEST_PROVIDER_URI, '--poa'
    ]

    user_input = '0\n' + 'Y\n' + (f'{INSECURE_SECRETS[1]}\n' * 8) + 'DEPLOY'
    result = click_runner.invoke(deploy,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Ensure there is a report on each contract
    for registry_name in Deployer.contract_names:
        assert registry_name in result.output

    # Check that the primary contract registry was written
    # and peek at some of the registered entries
    assert os.path.isfile(mock_primary_registry_filepath)
    with open(mock_primary_registry_filepath, 'r') as file:

        # Ensure every contract's name was written to the file, somehow
        raw_registry_data = file.read()
        for registry_name in Deployer.contract_names:
            assert registry_name in raw_registry_data

        # Ensure the Registry is JSON deserializable
        registry_data = json.loads(raw_registry_data)

        # and that is has the correct number of entries
        assert len(registry_data) == 9

        # Read several records
        token_record, escrow_record, dispatcher_record, *other_records = registry_data
        registered_name, registered_address, registered_abi = token_record

    #
    # Agency
    #

    token_agent = NucypherTokenAgent()
    assert token_agent.contract_name == registered_name
    assert token_agent.registry_contract_name == registered_name
    assert token_agent.contract_address == registered_address

    # Now show that we can use contract Agency and read from the blockchain
    assert token_agent.get_balance() == 0
    staking_agent = StakingEscrowAgent()
    assert staking_agent.get_current_period()

    # and at least the others can be instantiated
    assert PolicyAgent()