def test_transacting_power_sign_transaction(testerchain):

    eth_address = testerchain.unassigned_accounts[2]
    power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD,
                             signer=Web3Signer(testerchain.client),
                             account=eth_address)

    transaction_dict = {
        'nonce': testerchain.client.w3.eth.getTransactionCount(eth_address),
        'gasPrice': testerchain.client.w3.eth.gasPrice,
        'gas': 100000,
        'from': eth_address,
        'to': testerchain.unassigned_accounts[1],
        'value': 1,
        'data': b''
    }

    # Sign
    power.activate()
    signed_transaction = power.sign_transaction(
        transaction_dict=transaction_dict)

    # Demonstrate that the transaction is valid RLP encoded.
    from eth_account._utils.legacy_transactions import Transaction
    restored_transaction = Transaction.from_bytes(
        serialized_bytes=signed_transaction)
    restored_dict = restored_transaction.as_dict()
    assert to_checksum_address(restored_dict['to']) == transaction_dict['to']

    # Try signing with missing transaction fields
    del transaction_dict['gas']
    del transaction_dict['nonce']
    with pytest.raises(TypeError):
        power.sign_transaction(transaction_dict=transaction_dict)
def test_transacting_power_sign_agent_transaction(testerchain, agency,
                                                  test_registry):

    token_agent = NucypherTokenAgent(registry=test_registry)
    contract_function = token_agent.contract.functions.approve(
        testerchain.etherbase_account, 100)

    payload = {
        'chainId':
        int(testerchain.client.chain_id),
        'nonce':
        testerchain.client.w3.eth.getTransactionCount(
            testerchain.etherbase_account),
        'from':
        testerchain.etherbase_account,
        'gasPrice':
        testerchain.client.gas_price
    }

    unsigned_transaction = contract_function.buildTransaction(payload)

    # Sign with Transacting Power
    transacting_power = TransactingPower(
        password=INSECURE_DEVELOPMENT_PASSWORD,
        signer=Web3Signer(testerchain.client),
        account=testerchain.etherbase_account)
    signed_raw_transaction = transacting_power.sign_transaction(
        unsigned_transaction)

    # Demonstrate that the transaction is valid RLP encoded.
    restored_transaction = Transaction.from_bytes(
        serialized_bytes=signed_raw_transaction)
    restored_dict = restored_transaction.as_dict()
    assert to_checksum_address(
        restored_dict['to']) == unsigned_transaction['to']
Exemplo n.º 3
0
    def recover_transaction(self, serialized_transaction):
        """
        Get the address of the account that signed this transaction.

        :param serialized_transaction: the complete signed transaction
        :type serialized_transaction: hex str, bytes or int
        :returns: address of signer, hex-encoded & checksummed
        :rtype: str

        .. doctest:: python

            >>> raw_transaction = '0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428'  # noqa: E501
            >>> Account.recover_transaction(raw_transaction)
            '0x2c7536E3605D9C16a7a3D7b1898e529396a65c23'
        """
        txn_bytes = HexBytes(serialized_transaction)
        if len(txn_bytes) > 0 and txn_bytes[0] <= 0x7f:
            # We are dealing with a typed transaction.
            typed_transaction = TypedTransaction.from_bytes(txn_bytes)
            msg_hash = typed_transaction.hash()
            vrs = typed_transaction.vrs()
            return self._recover_hash(msg_hash, vrs=vrs)

        txn = Transaction.from_bytes(txn_bytes)
        msg_hash = hash_of_signed_transaction(txn)
        return self._recover_hash(msg_hash, vrs=vrs_from(txn))
def test_keystore_sign_transaction(good_signer, mock_account):
    transaction_dict = assoc(TRANSACTION_DICT,
                             'from',
                             value=mock_account.address)
    signed_transaction = good_signer.sign_transaction(
        transaction_dict=transaction_dict)
    assert isinstance(signed_transaction, HexBytes)

    # assert valid transaction
    transaction = Transaction.from_bytes(signed_transaction)
    assert to_checksum_address(transaction.to) == transaction_dict['to']
Exemplo n.º 5
0
def test_character_transacting_power_signing(testerchain, agency,
                                             test_registry):

    # Pretend to be a character.
    eth_address = testerchain.etherbase_account
    signer = Character(is_me=True,
                       eth_provider_uri=MOCK_ETH_PROVIDER_URI,
                       registry=test_registry,
                       checksum_address=eth_address)

    # Manually consume the power up
    transacting_power = TransactingPower(
        password=INSECURE_DEVELOPMENT_PASSWORD,
        signer=Web3Signer(testerchain.client),
        account=eth_address)

    signer._crypto_power.consume_power_up(transacting_power)

    # Retrieve the power up
    power = signer._crypto_power.power_ups(TransactingPower)

    assert power == transacting_power

    # Sign Message
    data_to_sign = b'Premium Select Luxury Pencil Holder'
    signature = power.sign_message(message=data_to_sign)
    is_verified = verify_eip_191(address=eth_address,
                                 message=data_to_sign,
                                 signature=signature)
    assert is_verified is True

    # Sign Transaction
    transaction_dict = {
        'nonce': testerchain.client.w3.eth.getTransactionCount(eth_address),
        'gasPrice': testerchain.client.w3.eth.gasPrice,
        'gas': 100000,
        'from': eth_address,
        'to': testerchain.unassigned_accounts[1],
        'value': 1,
        'data': b''
    }

    signed_transaction = power.sign_transaction(
        transaction_dict=transaction_dict)

    # Demonstrate that the transaction is valid RLP encoded.
    restored_transaction = Transaction.from_bytes(
        serialized_bytes=signed_transaction)
    restored_dict = restored_transaction.as_dict()
    assert to_checksum_address(restored_dict['to']) == transaction_dict['to']
Exemplo n.º 6
0
def test_trezor_sign_transaction(mock_trezor, mock_account):
    trezor_signer = TrezorSigner()
    transaction_dict = assoc(TRANSACTION_DICT,
                             key='from',
                             value=mock_account.address)
    signed_transaction = trezor_signer.sign_transaction(
        transaction_dict=transaction_dict)
    assert isinstance(signed_transaction, HexBytes)

    # assert valid deserializable transaction
    transaction = Transaction.from_bytes(signed_transaction)

    # Confirm the integrity of the sender and recipient address
    failure_message = 'WARNING: transaction "to" field was mutated'
    sender_checksum_address = to_checksum_address(transaction.to)
    assert sender_checksum_address != mock_account.address, failure_message
    assert sender_checksum_address == TRANSACTION_DICT['to'], failure_message
    assert sender_checksum_address == transaction_dict['to']  # positive
    assert sender_checksum_address != mock_account.address  # negative
Exemplo n.º 7
0
    def sign_transaction(self,
                         transaction_dict: dict,
                         rlp_encoded: bool = True
                         ) -> Union[HexBytes, Transaction]:
        """
        Sign a transaction with a trezor hardware wallet.

        This non-mutative method handles transaction validation, field formatting, signing,
        and outgoing serialization.  Accepts a standard transaction dictionary as input,
        and produces an RLP encoded raw signed transaction by default.

        Internally the standard transaction dictionary is reformatted for trezor API consumption
        via calls `trezorlib.client.ethereum.sign_tx`.

        WARNING: This function returns a raw signed transaction which can be
        broadcast by anyone with a connection to the ethereum network.

        ***Treat pre-signed raw transactions produced by this function like money.***

        """

        # Eager enforcement of EIP-155
        # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
        #
        # Leave the chain ID in tact for the trezor signing request so that an EIP-155 transaction signature will be applied
        # https://github.com/trezor/trezor-core/pull/311
        if 'chainId' not in transaction_dict:
            raise self.SignerError('Invalid EIP-155 transaction - "chain_id" field is missing in trezor signing request.')

        # Consume the sender inside the transaction request's 'from field.
        try:
            sender_address = transaction_dict['from']
        except KeyError:
            raise self.SignerError("'from' field is missing from trezor signing request.")
        transaction_dict = dissoc(transaction_dict, 'from')

        # Format contract data field for both trezor and eth_account's Transaction
        formatters = {'data': lambda data: Web3.toBytes(HexBytes(data))}
        transaction_dict = dict(apply_formatters_to_dict(formatters, transaction_dict))

        # Format transaction fields for Trezor, Lookup HD path
        trezor_transaction = self._format_transaction(transaction_dict=transaction_dict)

        # Note that the derivation path on the trezor must correlate with the chain id
        # in the transaction. Since Trezor firmware version 2.3.1 mismatched chain_id
        # and derivation path will fail to sign with 'forbidden key path'.
        # https://github.com/trezor/trezor-firmware/issues/1050#issuecomment-640718622
        hd_path = self.__get_address_path(checksum_address=sender_address)  # from cache

        # Trezor signing request
        _v, _r, _s = self.__sign_transaction(n=hd_path, trezor_transaction=trezor_transaction)

        # Create RLP serializable Transaction instance with eth_account
        # chainId is not longer needed since it can later be derived from v
        transaction_dict = dissoc(transaction_dict, 'chainId')

        # 'to' may be blank if this transaction is contract creation
        formatters = {'to': to_canonical_address}
        transaction_dict = dict(apply_formatters_to_dict(formatters, transaction_dict))

        signed_transaction = Transaction(v=to_int(_v),  # type: int
                                         r=to_int(_r),  # bytes -> int
                                         s=to_int(_s),  # bytes -> int
                                         **transaction_dict)

        # Optionally encode as RLP for broadcasting
        if rlp_encoded:
            signed_transaction = HexBytes(rlp.encode(signed_transaction))
        return signed_transaction