You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/python/src/trezorlib/ethereum.py

144 lines
4.0 KiB

# This file is part of the Trezor project.
#
# Copyright (C) 2012-2019 SatoshiLabs and contributors
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the License along with this library.
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
from . import exceptions, messages
from .tools import expect, normalize_nfc, session
def int_to_big_endian(value):
return value.to_bytes((value.bit_length() + 7) // 8, "big")
# ====== Client functions ====== #
@expect(messages.EthereumAddress, field="address")
def get_address(client, n, show_display=False, multisig=None):
return client.call(
messages.EthereumGetAddress(address_n=n, show_display=show_display)
)
@expect(messages.EthereumPublicKey)
def get_public_node(client, n, show_display=False):
return client.call(
messages.EthereumGetPublicKey(address_n=n, show_display=show_display)
)
@session
def sign_tx(
client,
n,
nonce,
gas_price,
gas_limit,
to,
value,
data=None,
chain_id=None,
tx_type=None,
):
msg = messages.EthereumSignTx(
address_n=n,
nonce=int_to_big_endian(nonce),
gas_price=int_to_big_endian(gas_price),
gas_limit=int_to_big_endian(gas_limit),
value=int_to_big_endian(value),
to=to,
chain_id=chain_id,
tx_type=tx_type,
)
if data:
msg.data_length = len(data)
data, chunk = data[1024:], data[:1024]
msg.data_initial_chunk = chunk
response = client.call(msg)
while response.data_length is not None:
data_length = response.data_length
data, chunk = data[data_length:], data[:data_length]
response = client.call(messages.EthereumTxAck(data_chunk=chunk))
# https://github.com/trezor/trezor-core/pull/311
# only signature bit returned. recalculate signature_v
if response.signature_v <= 1:
response.signature_v += 2 * chain_id + 35
return response.signature_v, response.signature_r, response.signature_s
@session
def sign_tx_eip1559(
client,
n,
*,
nonce,
gas_limit,
to,
value,
data=b"",
chain_id,
max_gas_fee,
max_priority_fee,
access_list=()
):
length = len(data)
data, chunk = data[1024:], data[:1024]
msg = messages.EthereumSignTxEIP1559(
address_n=n,
nonce=int_to_big_endian(nonce),
gas_limit=int_to_big_endian(gas_limit),
value=int_to_big_endian(value),
to=to,
chain_id=chain_id,
max_gas_fee=int_to_big_endian(max_gas_fee),
max_priority_fee=int_to_big_endian(max_priority_fee),
access_list=access_list,
data_length=length,
data_initial_chunk=chunk,
)
response = client.call(msg)
while response.data_length is not None:
data_length = response.data_length
data, chunk = data[data_length:], data[:data_length]
response = client.call(messages.EthereumTxAck(data_chunk=chunk))
return response.signature_v, response.signature_r, response.signature_s
@expect(messages.EthereumMessageSignature)
def sign_message(client, n, message):
message = normalize_nfc(message)
return client.call(messages.EthereumSignMessage(address_n=n, message=message))
def verify_message(client, address, signature, message):
message = normalize_nfc(message)
try:
resp = client.call(
messages.EthereumVerifyMessage(
address=address, signature=signature, message=message
)
)
except exceptions.TrezorFailure:
return False
return isinstance(resp, messages.Success)