diff --git a/src/apps/common/signtx.py b/src/apps/common/signtx.py index 32365b19d9..f6ddffe857 100644 --- a/src/apps/common/signtx.py +++ b/src/apps/common/signtx.py @@ -39,6 +39,13 @@ class UiConfirmTotal: self.coin = coin +class UiConfirmFeeOverThreshold: + + def __init__(self, fee: int, coin: CoinType): + self.fee = fee + self.coin = coin + + def confirm_output(output: TxOutputType, coin: CoinType): return (yield UiConfirmOutput(output, coin)) @@ -47,6 +54,10 @@ def confirm_total(spending: int, fee: int, coin: CoinType): return (yield UiConfirmTotal(spending, fee, coin)) +def confirm_feeoverthreshold(fee: int, coin: CoinType): + return (yield UiConfirmFeeOverThreshold(fee, coin)) + + def request_tx_meta(tx_req: TxRequest, tx_hash: bytes=None): tx_req.request_type = TXMETA tx_req.details.tx_hash = tx_hash @@ -83,6 +94,8 @@ def request_tx_finish(tx_req: TxRequest): yield tx_req tx_req.serialized = None +def estimate_tx_size(inputs, outputs): + return 10 + inputs * 149 + outputs * 35 # Transaction signing # === @@ -145,6 +158,12 @@ async def sign_tx(tx: SignTx, root): raise SigningError(FailureType.NotEnoughFunds, 'Not enough funds') + if fee > coin.maxfee_kb * ((estimate_tx_size(tx_inputs_count, tx_outputs_count) + 999) // 1000): + if not await confirm_feeoverthreshold(fee, coin): + raise SigningError(FailureType.ActionCancelled, + 'Signing cancelled') + + if not await confirm_total(total_out - change_out, fee, coin): raise SigningError(FailureType.ActionCancelled, 'Total cancelled') diff --git a/src/apps/wallet/__init__.py b/src/apps/wallet/__init__.py index 1830db5c8d..e1f07e09f4 100644 --- a/src/apps/wallet/__init__.py +++ b/src/apps/wallet/__init__.py @@ -25,8 +25,9 @@ def dispatch_SignTx(*args, **kwargs): @unimport async def dispatch_EstimateTxSize(msg, session_id): from trezor.messages.TxSize import TxSize + from ..common.signtx import estimate_tx_size m = TxSize() - m.tx_size = 10 + msg.inputs_count * 149 + msg.outputs_count * 35 + m.tx_size = estimate_tx_size(msg.inputs_count, msg.outputs_count) return m diff --git a/src/apps/wallet/layout_sign_tx.py b/src/apps/wallet/layout_sign_tx.py index 9f525e5b6c..43a13602c8 100644 --- a/src/apps/wallet/layout_sign_tx.py +++ b/src/apps/wallet/layout_sign_tx.py @@ -32,7 +32,18 @@ async def confirm_total(session_id, spending, fee, coin): return await hold_to_confirm(session_id, content, SignTx) -# @unimport +async def confirm_feeoverthreshold(session_id, fee, coin): + from trezor import ui + from trezor.ui.text import Text + from trezor.messages.ButtonRequestType import FeeOverThreshold + from ..common.confirm import confirm + + content = Text('Confirm high fee:', ui.ICON_RESET, + ui.BOLD, format_amount(fee, coin)) + return await confirm(session_id, content, FeeOverThreshold) + + +@unimport async def layout_sign_tx(message, session_id): from ..common.seed import get_root_node from ..common import signtx @@ -50,14 +61,16 @@ async def layout_sign_tx(message, session_id): req = signer.send(res) except signtx.SigningError as e: raise wire.FailureError(*e.args) - if isinstance(req, TxRequest): + if req.__qualname__ == 'TxRequest': if req.request_type == RequestType.TXFINISHED: break res = await wire.reply_message(session_id, req, TxAck) - elif isinstance(req, signtx.UiConfirmOutput): + elif req.__qualname__ == 'UiConfirmOutput': res = await confirm_output(session_id, req.output, req.coin) - elif isinstance(req, signtx.UiConfirmTotal): + elif req.__qualname__ == 'UiConfirmTotal': res = await confirm_total(session_id, req.spending, req.fee, req.coin) - else: + elif req.__qualname__ == 'UiConfirmFeeOverThreshold': + res = await confirm_feeoverthreshold(session_id, req.fee, req.coin) + else: raise ValueError('Invalid signing instruction') return req