Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show fee rate when signing transaction #2249

Merged
merged 1 commit into from
May 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/.changelog.d/2249.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Show the fee rate on the singing confirmation screen.
8 changes: 6 additions & 2 deletions core/src/apps/bitcoin/sign_tx/approvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,9 @@ async def approve_tx(self, tx_info: TxInfo, orig_txs: list[OriginalTxInfo]) -> N

total = self.total_in - self.change_out
spending = total - self.external_in
tx_size_vB = self.weight.get_total() / 4
# fee_threshold = (coin.maxfee per byte * tx size)
fee_threshold = (self.coin.maxfee_kb / 1000) * (self.weight.get_total() / 4)
fee_threshold = (self.coin.maxfee_kb / 1000) * tx_size_vB

# fee > (coin.maxfee per byte * tx size)
if fee > fee_threshold:
Expand Down Expand Up @@ -316,7 +317,10 @@ async def approve_tx(self, tx_info: TxInfo, orig_txs: list[OriginalTxInfo]) -> N
)

if not self.external_in:
await helpers.confirm_total(total, fee, self.coin, self.amount_unit)
fee_rate = fee / tx_size_vB
await helpers.confirm_total(
total, fee, fee_rate, self.coin, self.amount_unit
)
else:
await helpers.confirm_joint_total(
spending, total, self.coin, self.amount_unit
Expand Down
14 changes: 10 additions & 4 deletions core/src/apps/bitcoin/sign_tx/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,22 @@ def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:

class UiConfirmTotal(UiConfirm):
def __init__(
self, spending: int, fee: int, coin: CoinInfo, amount_unit: AmountUnit
self,
spending: int,
fee: int,
fee_rate: float,
coin: CoinInfo,
amount_unit: AmountUnit,
):
self.spending = spending
self.fee = fee
self.fee_rate = fee_rate
self.coin = coin
self.amount_unit = amount_unit

def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]:
return layout.confirm_total(
ctx, self.spending, self.fee, self.coin, self.amount_unit
ctx, self.spending, self.fee, self.fee_rate, self.coin, self.amount_unit
)


Expand Down Expand Up @@ -228,8 +234,8 @@ def confirm_modify_fee(user_fee_change: int, total_fee_new: int, coin: CoinInfo,
return (yield UiConfirmModifyFee(user_fee_change, total_fee_new, coin, amount_unit))


def confirm_total(spending: int, fee: int, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmTotal(spending, fee, coin, amount_unit))
def confirm_total(spending: int, fee: int, fee_rate: float, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmTotal(spending, fee, fee_rate, coin, amount_unit))


def confirm_joint_total(spending: int, total: int, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
Expand Down
7 changes: 7 additions & 0 deletions core/src/apps/bitcoin/sign_tx/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,20 @@ async def confirm_total(
ctx: wire.Context,
spending: int,
fee: int,
fee_rate: float,
coin: CoinInfo,
amount_unit: AmountUnit,
) -> None:
fee_rate_str: str | None = None

if fee_rate >= 0:
fee_rate_str = f"({fee_rate:.1f} sat/vB)"

await layouts.confirm_total(
ctx,
total_amount=format_coin_amount(spending, coin, amount_unit),
fee_amount=format_coin_amount(fee, coin, amount_unit),
fee_rate_amount=fee_rate_str,
)


Expand Down
5 changes: 5 additions & 0 deletions core/src/trezor/ui/layouts/tt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,7 @@ async def confirm_total(
ctx: wire.GenericContext,
total_amount: str,
fee_amount: str,
fee_rate_amount: str | None = None,
title: str = "Confirm transaction",
total_label: str = "Total amount:\n",
fee_label: str = "\nincluding fee:\n",
Expand All @@ -872,6 +873,10 @@ async def confirm_total(
text.bold(total_amount)
text.normal(fee_label)
text.bold(fee_amount)

if fee_rate_amount is not None:
text.normal("\n" + fee_rate_amount)

await raise_if_cancelled(interact(ctx, HoldToConfirm(text), br_type, br_code))


Expand Down
1 change: 1 addition & 0 deletions core/src/trezor/ui/layouts/tt_v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ async def confirm_total(
ctx: wire.GenericContext,
total_amount: str,
fee_amount: str,
fee_rate_amount: str | None = None,
title: str = "Confirm transaction",
total_label: str = "Total amount:\n",
fee_label: str = "\nincluding fee:\n",
Expand Down
11 changes: 9 additions & 2 deletions core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ def test_send_native_p2wpkh(self):
)
tx = SignTx(coin_name='Testnet', version=1, lock_time=0, inputs_count=1, outputs_count=2)

# precomputed tx weight is 566
fee_rate = 11000 / (566 / 4)

messages = [
None,

Expand All @@ -101,7 +104,7 @@ def test_send_native_p2wpkh(self):
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
True,

helpers.UiConfirmTotal(12300000, 11000, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(12300000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down Expand Up @@ -202,13 +205,17 @@ def test_send_native_p2wpkh_change(self):
)
out2 = TxOutput(
address=None,
# 49'/1'/0'/1/0" - 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0],
script_type=OutputScriptType.PAYTOWITNESS,
amount=12300000 - 11000 - 5000000,
multisig=None,
)
tx = SignTx(coin_name='Testnet', version=1, lock_time=0, inputs_count=1, outputs_count=2)

# precomputed tx weight is 566
fee_rate = 11000 / (566 / 4)

messages = [
None,

Expand All @@ -228,7 +235,7 @@ def test_send_native_p2wpkh_change(self):
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),

helpers.UiConfirmTotal(5000000 + 11000, 11000, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(5000000 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down
11 changes: 9 additions & 2 deletions core/tests/test_apps.bitcoin.segwit.signtx.native_p2wpkh_grs.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ def test_send_native_p2wpkh(self):
)
tx = SignTx(coin_name='Groestlcoin Testnet', version=1, lock_time=650713, inputs_count=1, outputs_count=2)

# precomputed tx weight is 566
fee_rate = 11000 / (566 / 4)

messages = [
None,

Expand All @@ -102,7 +105,7 @@ def test_send_native_p2wpkh(self):
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
True,

helpers.UiConfirmTotal(12300000, 11000, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(12300000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down Expand Up @@ -203,13 +206,17 @@ def test_send_native_p2wpkh_change(self):
)
out2 = TxOutput(
address=None,
# 84'/1'/0'/1/0" - tgrs1qejqxwzfld7zr6mf7ygqy5s5se5xq7vmt9lkd57
address_n=[84 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0],
script_type=OutputScriptType.PAYTOWITNESS,
amount=12300000 - 11000 - 5000000,
multisig=None,
)
tx = SignTx(coin_name='Groestlcoin Testnet', version=1, lock_time=650713, inputs_count=1, outputs_count=2)

# precomputed tx weight is 566
fee_rate = 11000 / (566 / 4)

messages = [
None,

Expand All @@ -229,7 +236,7 @@ def test_send_native_p2wpkh_change(self):
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
True,

helpers.UiConfirmTotal(5000000 + 11000, 11000, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(5000000 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down
15 changes: 12 additions & 3 deletions core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ def test_send_p2wpkh_in_p2sh(self):
)
tx = SignTx(coin_name='Testnet', version=1, lock_time=0, inputs_count=1, outputs_count=2)

# precomputed tx weight is 670
fee_rate = 11000 / (670 / 4)

messages = [
None,

Expand All @@ -98,7 +101,7 @@ def test_send_p2wpkh_in_p2sh(self):
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
True,

helpers.UiConfirmTotal(123445789 + 11000, 11000, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(123445789 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down Expand Up @@ -206,6 +209,9 @@ def test_send_p2wpkh_in_p2sh_change(self):
)
tx = SignTx(coin_name='Testnet', version=1, lock_time=0, inputs_count=1, outputs_count=2)

# precomputed tx weight is 670
fee_rate = 11000 / (670 / 4)

messages = [
None,

Expand All @@ -223,7 +229,7 @@ def test_send_p2wpkh_in_p2sh_change(self):
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),

helpers.UiConfirmTotal(12300000 + 11000, 11000, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(12300000 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down Expand Up @@ -352,6 +358,9 @@ def test_send_p2wpkh_in_p2sh_attack_amount(self):
)
tx = SignTx(coin_name='Testnet', version=1, lock_time=0, inputs_count=1, outputs_count=2)

# precomputed tx weight is 670
fee_rate = (9 - 8 - 1) / (670 / 4)

messages = [
None,

Expand All @@ -368,7 +377,7 @@ def test_send_p2wpkh_in_p2sh_attack_amount(self):
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),

helpers.UiConfirmTotal(9 - 1, 9 - 8 - 1, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(9 - 1, 9 - 8 - 1, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down
10 changes: 8 additions & 2 deletions core/tests/test_apps.bitcoin.segwit.signtx.p2wpkh_in_p2sh_grs.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ def test_send_p2wpkh_in_p2sh(self):
)
tx = SignTx(coin_name='Groestlcoin Testnet', version=1, lock_time=650756, inputs_count=1, outputs_count=2)

# precomputed tx weight is 670
fee_rate = 11000 / (670 / 4)

messages = [
None,

Expand All @@ -102,7 +105,7 @@ def test_send_p2wpkh_in_p2sh(self):
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
True,

helpers.UiConfirmTotal(123445789 + 11000, 11000, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(123445789 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down Expand Up @@ -210,6 +213,9 @@ def test_send_p2wpkh_in_p2sh_change(self):
)
tx = SignTx(coin_name='Groestlcoin Testnet', version=1, lock_time=650756, inputs_count=1, outputs_count=2)

# precomputed tx weight is 670
fee_rate = 11000 / (670 / 4)

messages = [
None,

Expand All @@ -229,7 +235,7 @@ def test_send_p2wpkh_in_p2sh_change(self):
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
True,

helpers.UiConfirmTotal(12300000 + 11000, 11000, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(12300000 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
True,

# check prev tx
Expand Down
5 changes: 4 additions & 1 deletion core/tests/test_apps.bitcoin.signtx.fee_threshold.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ def test_under_threshold(self):
address_n=[])
tx = SignTx(coin_name=None, version=1, lock_time=0, inputs_count=1, outputs_count=1)

# precomputed tx weight is 768
fee_rate = 90000 / (768 / 4)

messages = [
None,

Expand All @@ -145,7 +148,7 @@ def test_under_threshold(self):
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN),
True,
helpers.UiConfirmTotal(300000 + 90000, 90000, coin_bitcoin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(300000 + 90000, 90000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN),
True,
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAckInput(tx=TxAckInputWrapper(input=inp1)),
Expand Down
5 changes: 4 additions & 1 deletion core/tests/test_apps.bitcoin.signtx.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ def test_one_one_fee(self):
coin_name=None, version=1, lock_time=0, inputs_count=1, outputs_count=1
)

# precomputed tx weight is 768
fee_rate = 50_000 / (768 / 4)

messages = [
None,
TxRequest(
Expand All @@ -110,7 +113,7 @@ def test_one_one_fee(self):
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN),
True,
helpers.UiConfirmTotal(3_801_747, 50_000, coin_bitcoin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(3_801_747, 50_000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN),
True,
# ButtonRequest(code=ButtonRequest_ConfirmOutput),
# ButtonRequest(code=ButtonRequest_SignTx),
Expand Down
10 changes: 8 additions & 2 deletions core/tests/test_apps.bitcoin.signtx_decred.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ def test_one_one_fee(self):
outputs_count=1,
)

# precomputed tx weight is 768
fee_rate = 100_000 / (768 / 4)

messages = [
None,
TxRequest(
Expand All @@ -109,7 +112,7 @@ def test_one_one_fee(self):
helpers.UiConfirmOutput(out1, coin_decred, AmountUnit.BITCOIN),
True,
helpers.UiConfirmTotal(
200_000_000, 100_000, coin_decred, AmountUnit.BITCOIN
200_000_000, 100_000, fee_rate, coin_decred, AmountUnit.BITCOIN
),
True,
TxRequest(
Expand Down Expand Up @@ -243,6 +246,9 @@ def test_purchase_ticket(self):
decred_staking_ticket=True,
)

# precomputed tx weight is 1076
fee_rate = 100_000 / (1076 / 4)

messages = [
None,
TxRequest(
Expand Down Expand Up @@ -288,7 +294,7 @@ def test_purchase_ticket(self):
),
TxAckOutput(tx=TxAckOutputWrapper(output=out3)),
helpers.UiConfirmTotal(
200_000_000, 100_000, coin_decred, AmountUnit.BITCOIN
200_000_000, 100_000, fee_rate, coin_decred, AmountUnit.BITCOIN
),
True,
TxRequest(
Expand Down
5 changes: 4 additions & 1 deletion core/tests/test_apps.bitcoin.signtx_grs.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ def test_one_one_fee(self):
address_n=[])
tx = SignTx(coin_name='Groestlcoin', version=1, lock_time=0, inputs_count=1, outputs_count=1)

# precomputed tx weight is 768
fee_rate = 192 / (768 / 4)

messages = [
None,
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
Expand All @@ -69,7 +72,7 @@ def test_one_one_fee(self):
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
True,
helpers.UiConfirmTotal(210016, 192, coin, AmountUnit.BITCOIN),
helpers.UiConfirmTotal(210016, 192, fee_rate, coin, AmountUnit.BITCOIN),
True,
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAckInput(tx=TxAckInputWrapper(input=inp1)),
Expand Down
1 change: 1 addition & 0 deletions legacy/firmware/.changelog.d/2249.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Show the fee rate on the singing confirmation screen.
Loading