mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-02 03:48:58 +00:00
refactor(core/bitcoin): make use of Context omission to simplify bitcoin app
This commit is contained in:
parent
8538f3a65f
commit
5a4aaa79fc
@ -43,7 +43,7 @@ if TYPE_CHECKING:
|
|||||||
) -> None:
|
) -> None:
|
||||||
...
|
...
|
||||||
|
|
||||||
async def signer(self) -> None:
|
async def signer(self) -> TxRequest:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
@ -54,12 +54,8 @@ async def sign_tx(
|
|||||||
coin: CoinInfo,
|
coin: CoinInfo,
|
||||||
authorization: CoinJoinAuthorization | None = None,
|
authorization: CoinJoinAuthorization | None = None,
|
||||||
) -> TxRequest:
|
) -> TxRequest:
|
||||||
from trezor.enums import RequestType
|
|
||||||
from trezor.messages import TxRequest
|
|
||||||
from trezor.wire.context import call
|
|
||||||
|
|
||||||
from ..common import BITCOIN_NAMES
|
from ..common import BITCOIN_NAMES
|
||||||
from . import approvers, bitcoin, helpers, progress
|
from . import approvers, bitcoin
|
||||||
|
|
||||||
approver: approvers.Approver | None = None
|
approver: approvers.Approver | None = None
|
||||||
if authorization:
|
if authorization:
|
||||||
@ -86,19 +82,4 @@ async def sign_tx(
|
|||||||
|
|
||||||
signer_class = bitcoinlike.Bitcoinlike
|
signer_class = bitcoinlike.Bitcoinlike
|
||||||
|
|
||||||
signer = signer_class(msg, keychain, coin, approver).signer()
|
return await signer_class(msg, keychain, coin, approver).signer()
|
||||||
|
|
||||||
res: TxAckType | bool | None = None
|
|
||||||
while True:
|
|
||||||
req = signer.send(res)
|
|
||||||
if isinstance(req, tuple):
|
|
||||||
request_class, req = req
|
|
||||||
assert TxRequest.is_type_of(req)
|
|
||||||
if req.request_type == RequestType.TXFINISHED:
|
|
||||||
return req
|
|
||||||
res = await call(req, request_class)
|
|
||||||
elif isinstance(req, helpers.UiConfirm):
|
|
||||||
res = await req.confirm_dialog()
|
|
||||||
progress.progress.report_init()
|
|
||||||
else:
|
|
||||||
raise TypeError("Invalid signing instruction")
|
|
||||||
|
@ -11,7 +11,7 @@ from apps.common import safety_checks
|
|||||||
from .. import writers
|
from .. import writers
|
||||||
from ..common import input_is_external_unverified
|
from ..common import input_is_external_unverified
|
||||||
from ..keychain import SLIP44_TESTNET, validate_path_against_script_type
|
from ..keychain import SLIP44_TESTNET, validate_path_against_script_type
|
||||||
from . import helpers, tx_weight
|
from . import layout, tx_weight
|
||||||
from .sig_hasher import BitcoinSigHasher
|
from .sig_hasher import BitcoinSigHasher
|
||||||
from .tx_info import OriginalTxInfo
|
from .tx_info import OriginalTxInfo
|
||||||
|
|
||||||
@ -147,8 +147,10 @@ class BasicApprover(Approver):
|
|||||||
self.chunkify = bool(tx.chunkify)
|
self.chunkify = bool(tx.chunkify)
|
||||||
|
|
||||||
async def add_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None:
|
async def add_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None:
|
||||||
|
from apps.common.paths import show_path_warning
|
||||||
|
|
||||||
if not validate_path_against_script_type(self.coin, txi):
|
if not validate_path_against_script_type(self.coin, txi):
|
||||||
await helpers.confirm_foreign_address(txi.address_n)
|
await show_path_warning(txi.address_n)
|
||||||
self.foreign_address_confirmed = True
|
self.foreign_address_confirmed = True
|
||||||
|
|
||||||
await super().add_internal_input(txi, node)
|
await super().add_internal_input(txi, node)
|
||||||
@ -165,6 +167,8 @@ class BasicApprover(Approver):
|
|||||||
raise ProcessError("Transaction has changed during signing")
|
raise ProcessError("Transaction has changed during signing")
|
||||||
|
|
||||||
async def _add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
|
async def _add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
|
||||||
|
from apps.common.paths import show_path_warning
|
||||||
|
|
||||||
from ..common import CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES
|
from ..common import CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES
|
||||||
|
|
||||||
if txo.address_n and not validate_path_against_script_type(
|
if txo.address_n and not validate_path_against_script_type(
|
||||||
@ -173,7 +177,7 @@ class BasicApprover(Approver):
|
|||||||
script_type=CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES[txo.script_type],
|
script_type=CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES[txo.script_type],
|
||||||
multisig=bool(txo.multisig),
|
multisig=bool(txo.multisig),
|
||||||
):
|
):
|
||||||
await helpers.confirm_foreign_address(txo.address_n)
|
await show_path_warning(txo.address_n)
|
||||||
|
|
||||||
await super()._add_output(txo, script_pubkey)
|
await super()._add_output(txo, script_pubkey)
|
||||||
|
|
||||||
@ -202,7 +206,7 @@ class BasicApprover(Approver):
|
|||||||
raise ProcessError(
|
raise ProcessError(
|
||||||
"Reducing original output amounts is not supported."
|
"Reducing original output amounts is not supported."
|
||||||
)
|
)
|
||||||
await helpers.confirm_modify_output(
|
await layout.confirm_modify_output(
|
||||||
txo, orig_txo, self.coin, self.amount_unit
|
txo, orig_txo, self.coin, self.amount_unit
|
||||||
)
|
)
|
||||||
elif txo.amount > orig_txo.amount:
|
elif txo.amount > orig_txo.amount:
|
||||||
@ -224,7 +228,7 @@ class BasicApprover(Approver):
|
|||||||
elif txo.payment_req_index is None or self.show_payment_req_details:
|
elif txo.payment_req_index is None or self.show_payment_req_details:
|
||||||
# Ask user to confirm output, unless it is part of a payment
|
# Ask user to confirm output, unless it is part of a payment
|
||||||
# request, which gets confirmed separately.
|
# request, which gets confirmed separately.
|
||||||
await helpers.confirm_output(
|
await layout.confirm_output(
|
||||||
txo,
|
txo,
|
||||||
self.coin,
|
self.coin,
|
||||||
self.amount_unit,
|
self.amount_unit,
|
||||||
@ -240,7 +244,7 @@ class BasicApprover(Approver):
|
|||||||
if msg.amount is None:
|
if msg.amount is None:
|
||||||
raise DataError("Missing payment request amount.")
|
raise DataError("Missing payment request amount.")
|
||||||
|
|
||||||
result = await helpers.confirm_payment_request(msg, self.coin, self.amount_unit)
|
result = await layout.confirm_payment_request(msg, self.coin, self.amount_unit)
|
||||||
# When user wants to see more info, the result will be False.
|
# When user wants to see more info, the result will be False.
|
||||||
self.show_payment_req_details = result is False
|
self.show_payment_req_details = result is False
|
||||||
|
|
||||||
@ -252,7 +256,7 @@ class BasicApprover(Approver):
|
|||||||
|
|
||||||
title = self._replacement_title(tx_info, orig_txs)
|
title = self._replacement_title(tx_info, orig_txs)
|
||||||
for orig in orig_txs:
|
for orig in orig_txs:
|
||||||
await helpers.confirm_replacement(title, orig.orig_hash)
|
await layout.confirm_replacement(title, orig.orig_hash)
|
||||||
|
|
||||||
def _replacement_title(
|
def _replacement_title(
|
||||||
self, tx_info: TxInfo, orig_txs: list[OriginalTxInfo]
|
self, tx_info: TxInfo, orig_txs: list[OriginalTxInfo]
|
||||||
@ -277,10 +281,10 @@ class BasicApprover(Approver):
|
|||||||
await super().approve_tx(tx_info, orig_txs)
|
await super().approve_tx(tx_info, orig_txs)
|
||||||
|
|
||||||
if self.has_unverified_external_input:
|
if self.has_unverified_external_input:
|
||||||
await helpers.confirm_unverified_external_input()
|
await layout.confirm_unverified_external_input()
|
||||||
|
|
||||||
if tx_info.wallet_path.get_path() is None:
|
if tx_info.wallet_path.get_path() is None:
|
||||||
await helpers.confirm_multiple_accounts()
|
await layout.confirm_multiple_accounts()
|
||||||
|
|
||||||
fee = self.total_in - self.total_out
|
fee = self.total_in - self.total_out
|
||||||
|
|
||||||
@ -299,10 +303,10 @@ class BasicApprover(Approver):
|
|||||||
if fee > fee_threshold:
|
if fee > fee_threshold:
|
||||||
if fee > 10 * fee_threshold and safety_checks.is_strict():
|
if fee > 10 * fee_threshold and safety_checks.is_strict():
|
||||||
raise DataError("The fee is unexpectedly large")
|
raise DataError("The fee is unexpectedly large")
|
||||||
await helpers.confirm_feeoverthreshold(fee, coin, amount_unit)
|
await layout.confirm_feeoverthreshold(fee, coin, amount_unit)
|
||||||
|
|
||||||
if self.change_count > self.MAX_SILENT_CHANGE_COUNT:
|
if self.change_count > self.MAX_SILENT_CHANGE_COUNT:
|
||||||
await helpers.confirm_change_count_over_threshold(self.change_count)
|
await layout.confirm_change_count_over_threshold(self.change_count)
|
||||||
|
|
||||||
if orig_txs:
|
if orig_txs:
|
||||||
# Replacement transaction.
|
# Replacement transaction.
|
||||||
@ -338,7 +342,7 @@ class BasicApprover(Approver):
|
|||||||
# Not a PayJoin: Show the actual fee difference, since any difference in the fee is
|
# Not a PayJoin: Show the actual fee difference, since any difference in the fee is
|
||||||
# coming entirely from the user's own funds and from decreases of external outputs.
|
# coming entirely from the user's own funds and from decreases of external outputs.
|
||||||
# We consider the decreases as belonging to the user.
|
# We consider the decreases as belonging to the user.
|
||||||
await helpers.confirm_modify_fee(
|
await layout.confirm_modify_fee(
|
||||||
title, fee - orig_fee, fee, fee_rate, coin, amount_unit
|
title, fee - orig_fee, fee, fee_rate, coin, amount_unit
|
||||||
)
|
)
|
||||||
elif spending > orig_spending:
|
elif spending > orig_spending:
|
||||||
@ -346,7 +350,7 @@ class BasicApprover(Approver):
|
|||||||
# PayJoin and user is spending more: Show the increase in the user's contribution
|
# PayJoin and user is spending more: Show the increase in the user's contribution
|
||||||
# to the fee, ignoring any contribution from external inputs. Decreasing of
|
# to the fee, ignoring any contribution from external inputs. Decreasing of
|
||||||
# external outputs is not allowed in PayJoin, so there is no need to handle those.
|
# external outputs is not allowed in PayJoin, so there is no need to handle those.
|
||||||
await helpers.confirm_modify_fee(
|
await layout.confirm_modify_fee(
|
||||||
title, spending - orig_spending, fee, fee_rate, coin, amount_unit
|
title, spending - orig_spending, fee, fee_rate, coin, amount_unit
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -357,12 +361,12 @@ class BasicApprover(Approver):
|
|||||||
else:
|
else:
|
||||||
# Standard transaction.
|
# Standard transaction.
|
||||||
if tx_info.tx.lock_time > 0:
|
if tx_info.tx.lock_time > 0:
|
||||||
await helpers.confirm_nondefault_locktime(
|
await layout.confirm_nondefault_locktime(
|
||||||
tx_info.tx.lock_time, tx_info.lock_time_disabled()
|
tx_info.tx.lock_time, tx_info.lock_time_disabled()
|
||||||
)
|
)
|
||||||
|
|
||||||
if not self.external_in:
|
if not self.external_in:
|
||||||
await helpers.confirm_total(
|
await layout.confirm_total(
|
||||||
total,
|
total,
|
||||||
fee,
|
fee,
|
||||||
fee_rate,
|
fee_rate,
|
||||||
@ -371,7 +375,7 @@ class BasicApprover(Approver):
|
|||||||
tx_info.wallet_path.get_path(),
|
tx_info.wallet_path.get_path(),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await helpers.confirm_joint_total(spending, total, coin, amount_unit)
|
await layout.confirm_joint_total(spending, total, coin, amount_unit)
|
||||||
|
|
||||||
|
|
||||||
class CoinJoinApprover(Approver):
|
class CoinJoinApprover(Approver):
|
||||||
|
@ -23,7 +23,15 @@ if TYPE_CHECKING:
|
|||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
from trezor.crypto import bip32
|
from trezor.crypto import bip32
|
||||||
from trezor.messages import PrevInput, PrevOutput, PrevTx, SignTx, TxInput, TxOutput
|
from trezor.messages import (
|
||||||
|
PrevInput,
|
||||||
|
PrevOutput,
|
||||||
|
PrevTx,
|
||||||
|
SignTx,
|
||||||
|
TxInput,
|
||||||
|
TxOutput,
|
||||||
|
TxRequest,
|
||||||
|
)
|
||||||
|
|
||||||
from apps.common.coininfo import CoinInfo
|
from apps.common.coininfo import CoinInfo
|
||||||
from apps.common.keychain import Keychain
|
from apps.common.keychain import Keychain
|
||||||
@ -40,7 +48,7 @@ _SERIALIZED_TX_BUFFER = empty_bytearray(_MAX_SERIALIZED_CHUNK_SIZE)
|
|||||||
|
|
||||||
|
|
||||||
class Bitcoin:
|
class Bitcoin:
|
||||||
async def signer(self) -> None:
|
async def signer(self) -> TxRequest:
|
||||||
progress.init(
|
progress.init(
|
||||||
self.tx_info.tx, is_coinjoin=isinstance(self.approver, CoinJoinApprover)
|
self.tx_info.tx, is_coinjoin=isinstance(self.approver, CoinJoinApprover)
|
||||||
)
|
)
|
||||||
@ -87,9 +95,12 @@ class Bitcoin:
|
|||||||
# Sign segwit inputs and serialize witness data.
|
# Sign segwit inputs and serialize witness data.
|
||||||
await self.step6_sign_segwit_inputs()
|
await self.step6_sign_segwit_inputs()
|
||||||
|
|
||||||
# Write footer and send remaining data.
|
# Write footer and remaining data.
|
||||||
await self.step7_finish()
|
await self.step7_finish()
|
||||||
|
|
||||||
|
# Return the finishing message.
|
||||||
|
return helpers.finished_request(self.tx_req)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tx: SignTx,
|
tx: SignTx,
|
||||||
@ -333,7 +344,6 @@ class Bitcoin:
|
|||||||
self.write_tx_footer(self.serialized_tx, self.tx_info.tx)
|
self.write_tx_footer(self.serialized_tx, self.tx_info.tx)
|
||||||
if __debug__:
|
if __debug__:
|
||||||
progress.assert_finished()
|
progress.assert_finished()
|
||||||
await helpers.request_tx_finish(self.tx_req)
|
|
||||||
|
|
||||||
async def process_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None:
|
async def process_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None:
|
||||||
if txi.script_type not in common.INTERNAL_INPUT_SCRIPT_TYPES:
|
if txi.script_type not in common.INTERNAL_INPUT_SCRIPT_TYPES:
|
||||||
|
@ -90,10 +90,12 @@ class DecredApprover(BasicApprover):
|
|||||||
async def add_decred_sstx_submission(
|
async def add_decred_sstx_submission(
|
||||||
self, txo: TxOutput, script_pubkey: bytes
|
self, txo: TxOutput, script_pubkey: bytes
|
||||||
) -> None:
|
) -> None:
|
||||||
|
from .layout import confirm_decred_sstx_submission
|
||||||
|
|
||||||
# NOTE: The following calls Approver.add_external_output(), not BasicApprover.add_external_output().
|
# NOTE: The following calls Approver.add_external_output(), not BasicApprover.add_external_output().
|
||||||
# This is needed to skip calling helpers.confirm_output(), which is what BasicApprover would do.
|
# This is needed to skip calling helpers.confirm_output(), which is what BasicApprover would do.
|
||||||
await super(BasicApprover, self).add_external_output(txo, script_pubkey, None)
|
await super(BasicApprover, self).add_external_output(txo, script_pubkey, None)
|
||||||
await helpers.confirm_decred_sstx_submission(txo, self.coin, self.amount_unit)
|
await confirm_decred_sstx_submission(txo, self.coin, self.amount_unit)
|
||||||
|
|
||||||
|
|
||||||
class DecredSigHasher:
|
class DecredSigHasher:
|
||||||
@ -293,8 +295,6 @@ class Decred(Bitcoin):
|
|||||||
if __debug__:
|
if __debug__:
|
||||||
progress.assert_finished()
|
progress.assert_finished()
|
||||||
|
|
||||||
await helpers.request_tx_finish(self.tx_req)
|
|
||||||
|
|
||||||
def check_prevtx_output(self, txo_bin: PrevOutput) -> None:
|
def check_prevtx_output(self, txo_bin: PrevOutput) -> None:
|
||||||
if txo_bin.decred_script_version != 0:
|
if txo_bin.decred_script_version != 0:
|
||||||
raise ProcessError("Cannot use utxo that has script_version != 0")
|
raise ProcessError("Cannot use utxo that has script_version != 0")
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from trezor import utils
|
|
||||||
from trezor.enums import RequestType
|
from trezor.enums import RequestType
|
||||||
from trezor.wire import DataError
|
from trezor.wire import DataError
|
||||||
|
from trezor.wire.context import call
|
||||||
|
|
||||||
from .. import common
|
from .. import common
|
||||||
from ..writers import TX_HASH_SIZE
|
from ..writers import TX_HASH_SIZE
|
||||||
from . import layout
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, Awaitable
|
|
||||||
|
|
||||||
from trezor.enums import AmountUnit
|
|
||||||
from trezor.messages import (
|
from trezor.messages import (
|
||||||
PrevInput,
|
PrevInput,
|
||||||
PrevOutput,
|
PrevOutput,
|
||||||
@ -24,297 +20,24 @@ if TYPE_CHECKING:
|
|||||||
)
|
)
|
||||||
|
|
||||||
from apps.common.coininfo import CoinInfo
|
from apps.common.coininfo import CoinInfo
|
||||||
from apps.common.paths import Bip32Path
|
|
||||||
|
|
||||||
# Machine instructions
|
|
||||||
# ===
|
|
||||||
|
|
||||||
|
async def request_tx_meta(
|
||||||
class UiConfirm:
|
tx_req: TxRequest, coin: CoinInfo, tx_hash: bytes | None = None
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
) -> PrevTx:
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
__eq__ = utils.obj_eq
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmOutput(UiConfirm):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
output: TxOutput,
|
|
||||||
coin: CoinInfo,
|
|
||||||
amount_unit: AmountUnit,
|
|
||||||
output_index: int,
|
|
||||||
chunkify: bool,
|
|
||||||
):
|
|
||||||
self.output = output
|
|
||||||
self.coin = coin
|
|
||||||
self.amount_unit = amount_unit
|
|
||||||
self.output_index = output_index
|
|
||||||
self.chunkify = chunkify
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_output(
|
|
||||||
self.output,
|
|
||||||
self.coin,
|
|
||||||
self.amount_unit,
|
|
||||||
self.output_index,
|
|
||||||
self.chunkify,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmDecredSSTXSubmission(UiConfirm):
|
|
||||||
def __init__(self, output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit):
|
|
||||||
self.output = output
|
|
||||||
self.coin = coin
|
|
||||||
self.amount_unit = amount_unit
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_decred_sstx_submission(
|
|
||||||
self.output, self.coin, self.amount_unit
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmPaymentRequest(UiConfirm):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
payment_req: TxAckPaymentRequest,
|
|
||||||
coin: CoinInfo,
|
|
||||||
amount_unit: AmountUnit,
|
|
||||||
):
|
|
||||||
self.payment_req = payment_req
|
|
||||||
self.amount_unit = amount_unit
|
|
||||||
self.coin = coin
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_payment_request(
|
|
||||||
self.payment_req, self.coin, self.amount_unit
|
|
||||||
)
|
|
||||||
|
|
||||||
__eq__ = utils.obj_eq
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmReplacement(UiConfirm):
|
|
||||||
def __init__(self, title: str, txid: bytes):
|
|
||||||
self.title = title
|
|
||||||
self.txid = txid
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_replacement(self.title, self.txid)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmModifyOutput(UiConfirm):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
txo: TxOutput,
|
|
||||||
orig_txo: TxOutput,
|
|
||||||
coin: CoinInfo,
|
|
||||||
amount_unit: AmountUnit,
|
|
||||||
):
|
|
||||||
self.txo = txo
|
|
||||||
self.orig_txo = orig_txo
|
|
||||||
self.coin = coin
|
|
||||||
self.amount_unit = amount_unit
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_modify_output(
|
|
||||||
self.txo, self.orig_txo, self.coin, self.amount_unit
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmModifyFee(UiConfirm):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
title: str,
|
|
||||||
user_fee_change: int,
|
|
||||||
total_fee_new: int,
|
|
||||||
fee_rate: float,
|
|
||||||
coin: CoinInfo,
|
|
||||||
amount_unit: AmountUnit,
|
|
||||||
):
|
|
||||||
self.title = title
|
|
||||||
self.user_fee_change = user_fee_change
|
|
||||||
self.total_fee_new = total_fee_new
|
|
||||||
self.fee_rate = fee_rate
|
|
||||||
self.coin = coin
|
|
||||||
self.amount_unit = amount_unit
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_modify_fee(
|
|
||||||
self.title,
|
|
||||||
self.user_fee_change,
|
|
||||||
self.total_fee_new,
|
|
||||||
self.fee_rate,
|
|
||||||
self.coin,
|
|
||||||
self.amount_unit,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmTotal(UiConfirm):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
spending: int,
|
|
||||||
fee: int,
|
|
||||||
fee_rate: float,
|
|
||||||
coin: CoinInfo,
|
|
||||||
amount_unit: AmountUnit,
|
|
||||||
address_n: Bip32Path | None,
|
|
||||||
):
|
|
||||||
self.spending = spending
|
|
||||||
self.fee = fee
|
|
||||||
self.fee_rate = fee_rate
|
|
||||||
self.coin = coin
|
|
||||||
self.amount_unit = amount_unit
|
|
||||||
self.address_n = address_n
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_total(
|
|
||||||
self.spending,
|
|
||||||
self.fee,
|
|
||||||
self.fee_rate,
|
|
||||||
self.coin,
|
|
||||||
self.amount_unit,
|
|
||||||
self.address_n,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmJointTotal(UiConfirm):
|
|
||||||
def __init__(
|
|
||||||
self, spending: int, total: int, coin: CoinInfo, amount_unit: AmountUnit
|
|
||||||
):
|
|
||||||
self.spending = spending
|
|
||||||
self.total = total
|
|
||||||
self.coin = coin
|
|
||||||
self.amount_unit = amount_unit
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_joint_total(
|
|
||||||
self.spending, self.total, self.coin, self.amount_unit
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmFeeOverThreshold(UiConfirm):
|
|
||||||
def __init__(self, fee: int, coin: CoinInfo, amount_unit: AmountUnit):
|
|
||||||
self.fee = fee
|
|
||||||
self.coin = coin
|
|
||||||
self.amount_unit = amount_unit
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_feeoverthreshold(self.fee, self.coin, self.amount_unit)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmChangeCountOverThreshold(UiConfirm):
|
|
||||||
def __init__(self, change_count: int):
|
|
||||||
self.change_count = change_count
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_change_count_over_threshold(self.change_count)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmUnverifiedExternalInput(UiConfirm):
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_unverified_external_input()
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmForeignAddress(UiConfirm):
|
|
||||||
def __init__(self, address_n: list):
|
|
||||||
self.address_n = address_n
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
from apps.common import paths
|
|
||||||
|
|
||||||
return paths.show_path_warning(self.address_n)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmNonDefaultLocktime(UiConfirm):
|
|
||||||
def __init__(self, lock_time: int, lock_time_disabled: bool):
|
|
||||||
self.lock_time = lock_time
|
|
||||||
self.lock_time_disabled = lock_time_disabled
|
|
||||||
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_nondefault_locktime(
|
|
||||||
self.lock_time, self.lock_time_disabled
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmMultipleAccounts(UiConfirm):
|
|
||||||
def confirm_dialog(self) -> Awaitable[Any]:
|
|
||||||
return layout.confirm_multiple_accounts()
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_output(output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit, output_index: int, chunkify: bool) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmOutput(output, coin, amount_unit, output_index, chunkify))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_decred_sstx_submission(output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmDecredSSTXSubmission(output, coin, amount_unit))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_payment_request(payment_req: TxAckPaymentRequest, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmPaymentRequest(payment_req, coin, amount_unit))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_replacement(description: str, txid: bytes) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmReplacement(description, txid))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_modify_output(txo: TxOutput, orig_txo: TxOutput, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmModifyOutput(txo, orig_txo, coin, amount_unit))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_modify_fee(title: str, user_fee_change: int, total_fee_new: int, fee_rate: float, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (
|
|
||||||
yield UiConfirmModifyFee(
|
|
||||||
title, user_fee_change, total_fee_new, fee_rate, coin, amount_unit
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_total(spending: int, fee: int, fee_rate: float, coin: CoinInfo, amount_unit: AmountUnit, address_n: Bip32Path | None) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmTotal(spending, fee, fee_rate, coin, amount_unit, address_n))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_joint_total(spending: int, total: int, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmJointTotal(spending, total, coin, amount_unit))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_feeoverthreshold(fee: int, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmFeeOverThreshold(fee, coin, amount_unit))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_change_count_over_threshold(change_count: int) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmChangeCountOverThreshold(change_count))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_unverified_external_input() -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmUnverifiedExternalInput())
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_foreign_address(address_n: list) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmForeignAddress(address_n))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_nondefault_locktime(lock_time: int, lock_time_disabled: bool) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmNonDefaultLocktime(lock_time, lock_time_disabled))
|
|
||||||
|
|
||||||
|
|
||||||
def confirm_multiple_accounts() -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
|
|
||||||
return (yield UiConfirmMultipleAccounts())
|
|
||||||
|
|
||||||
|
|
||||||
def request_tx_meta(tx_req: TxRequest, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[PrevTx]: # type: ignore [awaitable-is-generator]
|
|
||||||
from trezor.messages import TxAckPrevMeta
|
from trezor.messages import TxAckPrevMeta
|
||||||
|
|
||||||
assert tx_req.details is not None
|
assert tx_req.details is not None
|
||||||
tx_req.request_type = RequestType.TXMETA
|
tx_req.request_type = RequestType.TXMETA
|
||||||
tx_req.details.tx_hash = tx_hash
|
tx_req.details.tx_hash = tx_hash
|
||||||
ack = yield TxAckPrevMeta, tx_req
|
ack = await call(tx_req, TxAckPrevMeta)
|
||||||
_clear_tx_request(tx_req)
|
_clear_tx_request(tx_req)
|
||||||
return _sanitize_tx_meta(ack.tx, coin)
|
return _sanitize_tx_meta(ack.tx, coin)
|
||||||
|
|
||||||
|
|
||||||
def request_tx_extra_data(
|
async def request_tx_extra_data(
|
||||||
tx_req: TxRequest, offset: int, size: int, tx_hash: bytes | None = None
|
tx_req: TxRequest, offset: int, size: int, tx_hash: bytes | None = None
|
||||||
) -> Awaitable[bytearray]: # type: ignore [awaitable-is-generator]
|
) -> bytes:
|
||||||
from trezor.messages import TxAckPrevExtraData
|
from trezor.messages import TxAckPrevExtraData
|
||||||
|
|
||||||
details = tx_req.details # local_cache_attribute
|
details = tx_req.details # local_cache_attribute
|
||||||
@ -324,12 +47,14 @@ def request_tx_extra_data(
|
|||||||
details.extra_data_offset = offset
|
details.extra_data_offset = offset
|
||||||
details.extra_data_len = size
|
details.extra_data_len = size
|
||||||
details.tx_hash = tx_hash
|
details.tx_hash = tx_hash
|
||||||
ack = yield TxAckPrevExtraData, tx_req
|
ack = await call(tx_req, TxAckPrevExtraData)
|
||||||
_clear_tx_request(tx_req)
|
_clear_tx_request(tx_req)
|
||||||
return ack.tx.extra_data_chunk
|
return ack.tx.extra_data_chunk
|
||||||
|
|
||||||
|
|
||||||
def request_tx_input(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[TxInput]: # type: ignore [awaitable-is-generator]
|
async def request_tx_input(
|
||||||
|
tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None
|
||||||
|
) -> TxInput:
|
||||||
from trezor.messages import TxAckInput
|
from trezor.messages import TxAckInput
|
||||||
|
|
||||||
assert tx_req.details is not None
|
assert tx_req.details is not None
|
||||||
@ -339,24 +64,28 @@ def request_tx_input(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes |
|
|||||||
else:
|
else:
|
||||||
tx_req.request_type = RequestType.TXINPUT
|
tx_req.request_type = RequestType.TXINPUT
|
||||||
tx_req.details.request_index = i
|
tx_req.details.request_index = i
|
||||||
ack = yield TxAckInput, tx_req
|
ack = await call(tx_req, TxAckInput)
|
||||||
_clear_tx_request(tx_req)
|
_clear_tx_request(tx_req)
|
||||||
return _sanitize_tx_input(ack.tx.input, coin)
|
return _sanitize_tx_input(ack.tx.input, coin)
|
||||||
|
|
||||||
|
|
||||||
def request_tx_prev_input(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[PrevInput]: # type: ignore [awaitable-is-generator]
|
async def request_tx_prev_input(
|
||||||
|
tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None
|
||||||
|
) -> PrevInput:
|
||||||
from trezor.messages import TxAckPrevInput
|
from trezor.messages import TxAckPrevInput
|
||||||
|
|
||||||
assert tx_req.details is not None
|
assert tx_req.details is not None
|
||||||
tx_req.request_type = RequestType.TXINPUT
|
tx_req.request_type = RequestType.TXINPUT
|
||||||
tx_req.details.request_index = i
|
tx_req.details.request_index = i
|
||||||
tx_req.details.tx_hash = tx_hash
|
tx_req.details.tx_hash = tx_hash
|
||||||
ack = yield TxAckPrevInput, tx_req
|
ack = await call(tx_req, TxAckPrevInput)
|
||||||
_clear_tx_request(tx_req)
|
_clear_tx_request(tx_req)
|
||||||
return _sanitize_tx_prev_input(ack.tx.input, coin)
|
return _sanitize_tx_prev_input(ack.tx.input, coin)
|
||||||
|
|
||||||
|
|
||||||
def request_tx_output(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[TxOutput]: # type: ignore [awaitable-is-generator]
|
async def request_tx_output(
|
||||||
|
tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None
|
||||||
|
) -> TxOutput:
|
||||||
from trezor.messages import TxAckOutput
|
from trezor.messages import TxAckOutput
|
||||||
|
|
||||||
assert tx_req.details is not None
|
assert tx_req.details is not None
|
||||||
@ -366,39 +95,40 @@ def request_tx_output(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes
|
|||||||
else:
|
else:
|
||||||
tx_req.request_type = RequestType.TXOUTPUT
|
tx_req.request_type = RequestType.TXOUTPUT
|
||||||
tx_req.details.request_index = i
|
tx_req.details.request_index = i
|
||||||
ack = yield TxAckOutput, tx_req
|
ack = await call(tx_req, TxAckOutput)
|
||||||
_clear_tx_request(tx_req)
|
_clear_tx_request(tx_req)
|
||||||
return _sanitize_tx_output(ack.tx.output, coin)
|
return _sanitize_tx_output(ack.tx.output, coin)
|
||||||
|
|
||||||
|
|
||||||
def request_tx_prev_output(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[PrevOutput]: # type: ignore [awaitable-is-generator]
|
async def request_tx_prev_output(
|
||||||
|
tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None
|
||||||
|
) -> PrevOutput:
|
||||||
from trezor.messages import TxAckPrevOutput
|
from trezor.messages import TxAckPrevOutput
|
||||||
|
|
||||||
assert tx_req.details is not None
|
assert tx_req.details is not None
|
||||||
tx_req.request_type = RequestType.TXOUTPUT
|
tx_req.request_type = RequestType.TXOUTPUT
|
||||||
tx_req.details.request_index = i
|
tx_req.details.request_index = i
|
||||||
tx_req.details.tx_hash = tx_hash
|
tx_req.details.tx_hash = tx_hash
|
||||||
ack = yield TxAckPrevOutput, tx_req
|
ack = await call(tx_req, TxAckPrevOutput)
|
||||||
_clear_tx_request(tx_req)
|
_clear_tx_request(tx_req)
|
||||||
# return sanitize_tx_prev_output(ack.tx, coin) # no sanitize is required
|
# return sanitize_tx_prev_output(ack.tx, coin) # no sanitize is required
|
||||||
return ack.tx.output
|
return ack.tx.output
|
||||||
|
|
||||||
|
|
||||||
def request_payment_req(tx_req: TxRequest, i: int) -> Awaitable[TxAckPaymentRequest]: # type: ignore [awaitable-is-generator]
|
async def request_payment_req(tx_req: TxRequest, i: int) -> TxAckPaymentRequest:
|
||||||
from trezor.messages import TxAckPaymentRequest
|
from trezor.messages import TxAckPaymentRequest
|
||||||
|
|
||||||
assert tx_req.details is not None
|
assert tx_req.details is not None
|
||||||
tx_req.request_type = RequestType.TXPAYMENTREQ
|
tx_req.request_type = RequestType.TXPAYMENTREQ
|
||||||
tx_req.details.request_index = i
|
tx_req.details.request_index = i
|
||||||
ack = yield TxAckPaymentRequest, tx_req
|
ack = await call(tx_req, TxAckPaymentRequest)
|
||||||
_clear_tx_request(tx_req)
|
_clear_tx_request(tx_req)
|
||||||
return _sanitize_payment_req(ack)
|
return _sanitize_payment_req(ack)
|
||||||
|
|
||||||
|
|
||||||
def request_tx_finish(tx_req: TxRequest) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
|
def finished_request(tx_req: TxRequest) -> TxRequest:
|
||||||
tx_req.request_type = RequestType.TXFINISHED
|
tx_req.request_type = RequestType.TXFINISHED
|
||||||
yield None, tx_req
|
return tx_req
|
||||||
_clear_tx_request(tx_req)
|
|
||||||
|
|
||||||
|
|
||||||
def _clear_tx_request(tx_req: TxRequest) -> None:
|
def _clear_tx_request(tx_req: TxRequest) -> None:
|
||||||
|
@ -140,8 +140,6 @@ class ZcashV4(Bitcoinlike):
|
|||||||
async def step7_finish(self) -> None:
|
async def step7_finish(self) -> None:
|
||||||
from apps.common.writers import write_compact_size
|
from apps.common.writers import write_compact_size
|
||||||
|
|
||||||
from . import helpers
|
|
||||||
|
|
||||||
serialized_tx = self.serialized_tx # local_cache_attribute
|
serialized_tx = self.serialized_tx # local_cache_attribute
|
||||||
|
|
||||||
if self.serialize:
|
if self.serialize:
|
||||||
@ -152,8 +150,6 @@ class ZcashV4(Bitcoinlike):
|
|||||||
write_compact_size(serialized_tx, 0) # nShieldedOutput
|
write_compact_size(serialized_tx, 0) # nShieldedOutput
|
||||||
write_compact_size(serialized_tx, 0) # nJoinSplit
|
write_compact_size(serialized_tx, 0) # nJoinSplit
|
||||||
|
|
||||||
await helpers.request_tx_finish(self.tx_req)
|
|
||||||
|
|
||||||
async def sign_nonsegwit_input(self, i_sign: int) -> None:
|
async def sign_nonsegwit_input(self, i_sign: int) -> None:
|
||||||
await self.sign_nonsegwit_bip143_input(i_sign)
|
await self.sign_nonsegwit_bip143_input(i_sign)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user