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)
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)
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)
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