mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 12:28:09 +00:00
feat(legacy): Allow decreasing output amount in RBF transactions.
This commit is contained in:
parent
28918f46ec
commit
9aec5409b9
@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- Public key to ECDHSessionKey. [#1518]
|
- Public key to ECDHSessionKey. [#1518]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- Allow decreasing the output value in RBF transactions. [#1491]
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
@ -380,3 +381,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
[#1402]: https://github.com/trezor/trezor-firmware/pull/1402
|
[#1402]: https://github.com/trezor/trezor-firmware/pull/1402
|
||||||
[#1415]: https://github.com/trezor/trezor-firmware/pull/1415
|
[#1415]: https://github.com/trezor/trezor-firmware/pull/1415
|
||||||
[#1518]: https://github.com/trezor/trezor-firmware/pull/1518
|
[#1518]: https://github.com/trezor/trezor-firmware/pull/1518
|
||||||
|
[#1491]: https://github.com/trezor/trezor-firmware/issues/1491
|
||||||
|
@ -503,6 +503,37 @@ void layoutConfirmReplacement(const char *description, uint8_t txid[32]) {
|
|||||||
description, str[0], str[1], str[2], str[3], NULL);
|
description, str[0], str[1], str[2], str[3], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void layoutConfirmModifyOutput(const CoinInfo *coin, AmountUnit amount_unit,
|
||||||
|
TxOutputType *out, TxOutputType *orig_out,
|
||||||
|
int page) {
|
||||||
|
if (page == 0) {
|
||||||
|
render_address_dialog(coin, out->address, _("Modify amount for"),
|
||||||
|
_("address:"), NULL);
|
||||||
|
} else {
|
||||||
|
char *question = NULL;
|
||||||
|
uint64_t amount_change = 0;
|
||||||
|
if (orig_out->amount < out->amount) {
|
||||||
|
question = _("Increase amount by:");
|
||||||
|
amount_change = out->amount - orig_out->amount;
|
||||||
|
} else {
|
||||||
|
question = _("Decrease amount by:");
|
||||||
|
amount_change = orig_out->amount - out->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
char str_amount_change[32] = {0};
|
||||||
|
format_coin_amount(amount_change, NULL, coin, amount_unit,
|
||||||
|
str_amount_change, sizeof(str_amount_change));
|
||||||
|
|
||||||
|
char str_amount_new[32] = {0};
|
||||||
|
format_coin_amount(out->amount, NULL, coin, amount_unit, str_amount_new,
|
||||||
|
sizeof(str_amount_new));
|
||||||
|
|
||||||
|
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
|
||||||
|
question, str_amount_change, NULL, _("New amount:"),
|
||||||
|
str_amount_new, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit,
|
void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit,
|
||||||
uint64_t fee_old, uint64_t fee_new) {
|
uint64_t fee_old, uint64_t fee_new) {
|
||||||
char str_fee_change[32] = {0};
|
char str_fee_change[32] = {0};
|
||||||
|
@ -54,6 +54,9 @@ void layoutConfirmTx(const CoinInfo *coin, AmountUnit amount_unit,
|
|||||||
uint64_t total_in, uint64_t total_out,
|
uint64_t total_in, uint64_t total_out,
|
||||||
uint64_t change_out);
|
uint64_t change_out);
|
||||||
void layoutConfirmReplacement(const char *description, uint8_t txid[32]);
|
void layoutConfirmReplacement(const char *description, uint8_t txid[32]);
|
||||||
|
void layoutConfirmModifyOutput(const CoinInfo *coin, AmountUnit amount_unit,
|
||||||
|
TxOutputType *out, TxOutputType *orig_out,
|
||||||
|
int page);
|
||||||
void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit,
|
void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit,
|
||||||
uint64_t fee_old, uint64_t fee_new);
|
uint64_t fee_old, uint64_t fee_new);
|
||||||
void layoutFeeOverThreshold(const CoinInfo *coin, AmountUnit amount_unit,
|
void layoutFeeOverThreshold(const CoinInfo *coin, AmountUnit amount_unit,
|
||||||
|
@ -296,6 +296,10 @@ static bool add_amount(uint64_t *dest, uint64_t amount) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_rbf_enabled(TxInfo *tx_info) {
|
||||||
|
return tx_info->min_sequence <= MAX_BIP125_RBF_SEQUENCE;
|
||||||
|
}
|
||||||
|
|
||||||
void send_req_1_input(void) {
|
void send_req_1_input(void) {
|
||||||
signing_stage = STAGE_REQUEST_1_INPUT;
|
signing_stage = STAGE_REQUEST_1_INPUT;
|
||||||
resp.has_request_type = true;
|
resp.has_request_type = true;
|
||||||
@ -527,6 +531,21 @@ void phase1_request_next_input(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *description = NULL;
|
||||||
|
if (!is_rbf_enabled(&info) && is_rbf_enabled(&orig_info)) {
|
||||||
|
description = _("Finalize TXID:");
|
||||||
|
} else {
|
||||||
|
description = _("Update TXID:");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm original TXID.
|
||||||
|
layoutConfirmReplacement(description, orig_hash);
|
||||||
|
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
||||||
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
||||||
|
signing_abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
idx2 = 0;
|
idx2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1449,15 +1468,28 @@ static bool signing_check_orig_output(TxOutputType *orig_output) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replacement transactions must not decrease the value of any external
|
|
||||||
// outputs. Furthermore, the only way to increase the amount would be by
|
|
||||||
// supplying an external input, which is currently not supported, so the
|
|
||||||
// external output amounts must remain unchanged.
|
|
||||||
if (!is_change) {
|
if (!is_change) {
|
||||||
if (output.amount != orig_output->amount) {
|
if (output.amount < orig_output->amount) {
|
||||||
|
// Replacement transactions may need to decrease the value of external
|
||||||
|
// outputs to bump the fee. This is needed if the original transaction
|
||||||
|
// transfers the entire account balance ("Send Max").
|
||||||
|
for (int page = 0; page < 2; ++page) {
|
||||||
|
layoutConfirmModifyOutput(coin, amount_unit, &output, orig_output,
|
||||||
|
page);
|
||||||
|
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput,
|
||||||
|
false)) {
|
||||||
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
||||||
|
signing_abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (output.amount > orig_output->amount) {
|
||||||
|
// Only PayJoin transactions may increase the value of external outputs
|
||||||
|
// by supplying an external input. However, external inputs are
|
||||||
|
// currently not supported.
|
||||||
fsm_sendFailure(
|
fsm_sendFailure(
|
||||||
FailureType_Failure_ProcessError,
|
FailureType_Failure_ProcessError,
|
||||||
_("Changing original output amounts is not supported."));
|
_("Increasing original output amounts is not supported."));
|
||||||
signing_abort();
|
signing_abort();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1544,29 +1576,6 @@ static bool signing_confirm_tx(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rbf_disabled = info.min_sequence > MAX_BIP125_RBF_SEQUENCE;
|
|
||||||
bool orig_rbf_disabled = orig_info.min_sequence > MAX_BIP125_RBF_SEQUENCE;
|
|
||||||
char *description = NULL;
|
|
||||||
if (rbf_disabled && !orig_rbf_disabled) {
|
|
||||||
description = _("Finalize TXID:");
|
|
||||||
} else if (fee != orig_fee) {
|
|
||||||
description = _("Modify fee for TXID:");
|
|
||||||
} else {
|
|
||||||
// The host might want to modify nSequence on some inputs (e.g. to
|
|
||||||
// re-enable RBF on a transaction that was dropped from the mempool), add
|
|
||||||
// more inputs and consolidate them in a change-output or use a different
|
|
||||||
// change-output address.
|
|
||||||
description = _("Update TXID:");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm original TXID.
|
|
||||||
layoutConfirmReplacement(description, orig_hash);
|
|
||||||
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
|
|
||||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
||||||
signing_abort();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fee modification.
|
// Fee modification.
|
||||||
if (fee != orig_fee) {
|
if (fee != orig_fee) {
|
||||||
layoutConfirmModifyFee(coin, amount_unit, orig_fee, fee);
|
layoutConfirmModifyFee(coin, amount_unit, orig_fee, fee);
|
||||||
|
Loading…
Reference in New Issue
Block a user