Exemplo n.º 1
0
    def _encode_value(self, value):
        """Addresses are encoded like Uint160 numbers."""

        # Some smart conversions - need to get the address to a numeric before we encode it
        if isinstance(value, bytes):
            v = to_int(value)
        elif isinstance(value, str):
            v = to_int(hexstr=value)
        else:
            v = value  # Fallback, just use it as-is.
        return Uint(160).encode_value(v)
Exemplo n.º 2
0
def _get_evm_parameters(order, order_instrument, signer):
    abi_types = []
    evm_parameters = []

    # account
    abi_types.append('address')
    evm_parameters.append(to_checksum_address(order['accountId']))

    # originatorTimestamp
    abi_types.append('uint64')
    evm_parameters.append(to_int(order['timestamp']))

    # orderType
    abi_types.append('uint8')
    evm_parameters.append(to_int(_get_order_type_as_int(order['orderType'])))

    # side
    abi_types.append('uint8')
    evm_parameters.append(to_int(_get_side_as_int(order['side'])))

    # quantity
    abi_types.append('uint256')
    quantity = _convert_to_unit_lowest_denomination(
        order['quantity'], order_instrument['base']['decimals'])
    evm_parameters.append(quantity)

    # price
    abi_types.append('uint256')
    price = _convert_to_unit_lowest_denomination(
        order['price'], order_instrument['quote']['decimals'])
    evm_parameters.append(price)

    # base
    abi_types.append('address')
    evm_parameters.append(to_checksum_address(
        order_instrument['base']['address']))

    # quote
    abi_types.append('address')
    evm_parameters.append(to_checksum_address(
        order_instrument['quote']['address']))

    return (abi_types, evm_parameters)
Exemplo n.º 3
0
def _get_evm_parameters(order, order_instrument, signer):
    abi_types = []
    evm_parameters = []

    # account
    abi_types.append('address')
    evm_parameters.append(to_checksum_address(order['accountId']))

    # originatorTimestamp
    abi_types.append('uint64')
    evm_parameters.append(to_int(order['timestamp']))

    # orderType
    abi_types.append('uint8')
    evm_parameters.append(to_int(_get_order_type_as_int(order['orderType'])))

    # side
    abi_types.append('uint8')
    evm_parameters.append(to_int(_get_side_as_int(order['side'])))

    # instrument
    abi_types.append('uint32')
    evm_parameters.append(int(order['instrument']))

    # price
    abi_types.append('uint256')
    price = _convert_to_unit_lowest_denomination(
        order['price'], order_instrument['quote']['decimals'])
    evm_parameters.append(price)

    # marginPerUnit
    abi_types.append('uint256')
    evm_parameters.append(to_int(int(order['marginPerFraction'])))

    # asset
    abi_types.append('address')
    evm_parameters.append(to_checksum_address(order['quote']))

    # quantity
    (numerator,
     denominator) = get_quantity_numerator_and_denominator(order['quantity'])
    abi_types.append('uint64')
    evm_parameters.append(to_int(numerator))
    abi_types.append('uint64')
    evm_parameters.append(to_int(denominator))

    return (abi_types, evm_parameters)
Exemplo n.º 4
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