From 7d0cafecc301241e1b76213dad2a87be4373ce4a Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Wed, 27 Dec 2017 12:48:05 +0100 Subject: [PATCH] ethereum/singing: layout seperated --- src/apps/ethereum/layout.py | 59 +++++++++++++++++++++++++++++ src/apps/ethereum/sign_tx.py | 52 ++++++------------------- tests/test_apps.ethereum.layout.py | 30 +++++++++++++++ tests/test_apps.ethereum.sign_tx.py | 30 --------------- 4 files changed, 100 insertions(+), 71 deletions(-) create mode 100644 src/apps/ethereum/layout.py create mode 100644 tests/test_apps.ethereum.layout.py delete mode 100644 tests/test_apps.ethereum.sign_tx.py diff --git a/src/apps/ethereum/layout.py b/src/apps/ethereum/layout.py new file mode 100644 index 000000000..0ce207800 --- /dev/null +++ b/src/apps/ethereum/layout.py @@ -0,0 +1,59 @@ +from trezor import wire, ui +from trezor.utils import unimport, chunks +from trezor.messages import ButtonRequestType +from trezor.ui.text import Text +from apps.common.confirm import * +from . import networks + + +@unimport +async def confirm_tx(ctx, to, value, chain_id, token=None): + content = Text('Confirm transaction', ui.ICON_RESET, + ui.BOLD, format_amount(value, token, chain_id), + ui.NORMAL, 'to', + ui.MONO, *split_address(to)) # todo no addres shown, why? + return await confirm(ctx, content, ButtonRequestType.ConfirmOutput) + + +@unimport +async def confirm_fee(ctx, spending, fee, chain_id, token=None): + content = Text('Confirm transaction', ui.ICON_RESET, + 'Sending: %s' % format_amount(spending, token, chain_id), + 'Fee: %s' % format_amount(fee, token, chain_id)) + return await hold_to_confirm(ctx, content, ButtonRequestType.SignTx) + + +@unimport +async def confirm_data(ctx, data, data_total): + content = Text('Confirm data', ui.ICON_RESET, + ui.MONO, data[:16], # todo nothing displayed? + 'of total: ', data_total) + return await confirm(ctx, content, ButtonRequestType.ConfirmOutput) + + +@unimport +async def confirm_fee(ctx, value, gas_price, gas_limit, token): + content = Text('Confirm fee', ui.ICON_RESET, + 'price:', ui.MONO, gas_price, # todo wording + 'limit:', ui.MONO, gas_limit, + 'value: ', value) + return await confirm(ctx, content, ButtonRequestType.ConfirmOutput) + + +def split_address(address): + return chunks(address, 17) + + +def format_amount(value, token, chain_id): + value = int.from_bytes(value, 'little') + if token: + suffix = token.ticker + decimals = token.decimals + elif value < 1e18: + suffix = 'Wei' + decimals = 0 + else: + decimals = 18 + suffix = networks.suffix_by_chain_id(chain_id) + + return '%s %s' % (value // 10 ** decimals, suffix) diff --git a/src/apps/ethereum/sign_tx.py b/src/apps/ethereum/sign_tx.py index e20ef9459..a52cb1ad5 100644 --- a/src/apps/ethereum/sign_tx.py +++ b/src/apps/ethereum/sign_tx.py @@ -1,15 +1,10 @@ -from trezor import wire, ui from trezor.utils import unimport from trezor.messages.EthereumSignTx import EthereumSignTx from trezor.messages.EthereumTxRequest import EthereumTxRequest -from trezor.messages import ButtonRequestType from trezor.messages import FailureType -from apps.common.confirm import confirm from apps.common.hash_writer import HashWriter -from trezor.ui.text import Text from trezor.crypto import rlp -from apps.ethereum import networks, tokens - +from apps.ethereum import tokens, layout # maximum supported chain id MAX_CHAIN_ID = 2147483630 @@ -33,16 +28,16 @@ async def ethereum_sign_tx(ctx, msg): msg.data_initial_chunk[:16] == b'\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00': token = tokens.token_by_chain_address(msg.chain_id, msg.to) - if token is not None: - # todo: await layout_ethereum_confirm_tx(msg->data_initial_chunk.bytes + 16, 20, msg->data_initial_chunk.bytes + 36, 32, token); - await layout_ethereum_confirm_tx(ctx, msg.to, msg.value, msg.chain_id, token) + if token is None: + await layout.confirm_tx(ctx, msg.to, msg.value, msg.chain_id, token) else: - await layout_ethereum_confirm_tx(ctx, msg.to, msg.value, msg.chain_id, token) + # todo is this tested? + await layout.confirm_tx(ctx, msg.data_initial_chunk[16:36], msg.data_initial_chunk.bytes[36:68], msg.chain_id, token) - # if token == None and msg.data_length > 0: - # layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); + if token is None and msg.data_length > 0: + await layout.confirm_data(ctx, msg.data_initial_chunk, data_total) - # todo layoutEthereumFee + await layout.confirm_fee(ctx, msg.value, msg.gas_price, msg.gas_limit, token) data = bytearray() data += msg.data_initial_chunk @@ -63,7 +58,7 @@ async def ethereum_sign_tx(ctx, msg): sha.extend(rlp.encode(data, False)) while data_left > 0: - resp = await send_request_chunk(ctx, data_left, data_total) + resp = await send_request_chunk(ctx, data_left) data_left -= len(resp.data_chunk) sha.extend(resp.data_chunk) @@ -73,7 +68,7 @@ async def ethereum_sign_tx(ctx, msg): sha.extend(rlp.encode(0)) sha.extend(rlp.encode(0)) - digest = sha.get_digest(True) + digest = sha.get_digest(True) # True -> use keccak mode return await send_signature(ctx, msg, digest) @@ -91,7 +86,7 @@ def get_total_length(msg: EthereumSignTx, data_total: int) -> int: return length -async def send_request_chunk(ctx, data_left: int, data_total: int): +async def send_request_chunk(ctx, data_left: int): from trezor.messages.wire_types import EthereumTxAck # todo layoutProgress ? req = EthereumTxRequest() @@ -183,28 +178,3 @@ def sanitize(msg): if msg.chain_id is None: msg.chain_id = 0 return msg - - -@unimport -async def layout_ethereum_confirm_tx(ctx, to, value, chain_id, token=None): - content = Text('Confirm transaction', ui.ICON_RESET, - ui.BOLD, format_amount(value, token, chain_id), - ui.NORMAL, 'to', - ui.MONO, to) - - return await confirm(ctx, content, ButtonRequestType.ConfirmOutput) - - -def format_amount(value, token, chain_id): - value = int.from_bytes(value, 'little') - if token: - suffix = token.ticker - decimals = token.decimals - elif value < 1e18: - suffix = 'Wei' - decimals = 0 - else: - decimals = 18 - suffix = networks.suffix_by_chain_id(chain_id) - - return '%s %s' % (value // 10 ** decimals, suffix) diff --git a/tests/test_apps.ethereum.layout.py b/tests/test_apps.ethereum.layout.py new file mode 100644 index 000000000..2aed8384a --- /dev/null +++ b/tests/test_apps.ethereum.layout.py @@ -0,0 +1,30 @@ +from common import * +from apps.ethereum.layout import format_amount + + +class TestEthereumLayout(unittest.TestCase): + + def test_format(self): + text = format_amount((1).to_bytes(5, 'little'), None, 1) + self.assertEqual(text, '1 Wei') + text = format_amount((1000).to_bytes(5, 'little'), None, 1) + self.assertEqual(text, '1000 Wei') + + text = format_amount((1000000000000000001).to_bytes(20, 'little'), None, 1) + self.assertEqual(text, '1 ETH') + text = format_amount((10000000000000000001).to_bytes(20, 'little'), None, 1) + self.assertEqual(text, '10 ETH') + text = format_amount((10000000000000000001).to_bytes(20, 'little'), None, 61) + self.assertEqual(text, '10 ETC') + text = format_amount((1000000000000000001).to_bytes(20, 'little'), None, 31) + self.assertEqual(text, '1 tRSK') + + # unknown chain + text = format_amount((1).to_bytes(20, 'little'), None, 9999) + self.assertEqual(text, '1 Wei') + text = format_amount((10000000000000000001).to_bytes(20, 'little'), None, 9999) + self.assertEqual(text, '10 UNKN') + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_apps.ethereum.sign_tx.py b/tests/test_apps.ethereum.sign_tx.py deleted file mode 100644 index b3bf7f9f7..000000000 --- a/tests/test_apps.ethereum.sign_tx.py +++ /dev/null @@ -1,30 +0,0 @@ -from common import * -from apps.ethereum import sign_tx - - -class TestEthereumSignTx(unittest.TestCase): - - def test_format(self): - text = sign_tx.format_amount((1).to_bytes(5, 'little'), None, 1) - self.assertEqual(text, '1 Wei') - text = sign_tx.format_amount((1000).to_bytes(5, 'little'), None, 1) - self.assertEqual(text, '1000 Wei') - - text = sign_tx.format_amount((1000000000000000001).to_bytes(20, 'little'), None, 1) - self.assertEqual(text, '1 ETH') - text = sign_tx.format_amount((10000000000000000001).to_bytes(20, 'little'), None, 1) - self.assertEqual(text, '10 ETH') - text = sign_tx.format_amount((10000000000000000001).to_bytes(20, 'little'), None, 61) - self.assertEqual(text, '10 ETC') - text = sign_tx.format_amount((1000000000000000001).to_bytes(20, 'little'), None, 31) - self.assertEqual(text, '1 tRSK') - - # unknown chain - text = sign_tx.format_amount((1).to_bytes(20, 'little'), None, 9999) - self.assertEqual(text, '1 Wei') - text = sign_tx.format_amount((10000000000000000001).to_bytes(20, 'little'), None, 9999) - self.assertEqual(text, '10 UNKN') - - -if __name__ == '__main__': - unittest.main()