From 0aa87e39a0cb407ba0a1854e9291595cc74698cd Mon Sep 17 00:00:00 2001 From: Michele Balistreri Date: Tue, 13 Aug 2024 10:06:53 +0200 Subject: [PATCH] add more details to btc tx description --- app/bitcoin/bitcoin.h | 1 + app/core/core_btc.c | 11 +++++++++ app/ui/dialog.c | 54 ++++++++++++++++++++++++++++++++++++------- app/ui/english.c | 3 +++ app/ui/i18n.h | 7 ++++-- 5 files changed, 66 insertions(+), 10 deletions(-) diff --git a/app/bitcoin/bitcoin.h b/app/bitcoin/bitcoin.h index aa38af6..737ad9b 100644 --- a/app/bitcoin/bitcoin.h +++ b/app/bitcoin/bitcoin.h @@ -49,6 +49,7 @@ typedef struct { psbt_txin_t inputs[BTC_MAX_INPUTS]; psbt_txout_t outputs[BTC_MAX_OUTPUTS]; psbt_input_data_t input_data[BTC_MAX_INPUTS]; + bool output_is_change[BTC_MAX_OUTPUTS]; size_t input_count; size_t output_count; diff --git a/app/core/core_btc.c b/app/core/core_btc.c index d9d8af3..ad9d54d 100644 --- a/app/core/core_btc.c +++ b/app/core/core_btc.c @@ -533,6 +533,17 @@ static app_err_t core_btc_validate(btc_tx_ctx_t* tx_ctx) { } } + for (int i = 0; i < tx_ctx->output_count; i++) { + for (int j = 0; j < tx_ctx->input_count; j++) { + if (tx_ctx->input_data[j].can_sign && + (tx_ctx->input_data[j].script_pubkey_len == tx_ctx->outputs[i].script_len) && + !memcmp(tx_ctx->input_data[j].script_pubkey, tx_ctx->outputs[i].script, tx_ctx->outputs[i].script_len)) { + tx_ctx->output_is_change[i] = true; + break; + } + } + } + return can_sign_something ? ERR_OK : ERR_MISMATCH; } diff --git a/app/ui/dialog.c b/app/ui/dialog.c index 095087e..e89e3d1 100644 --- a/app/ui/dialog.c +++ b/app/ui/dialog.c @@ -287,11 +287,11 @@ static void dialog_indexed_string(char* dst, const char* label, size_t index) { // TODO: move this to more general function to recognize data and display correct data accordingly static i18n_str_id_t dialog_recognize_data(const txContent_t* tx) { if (tx->dataLength == 0) { - return TX_DATA_NONE; + return TX_NO; } else if (tx->value.length == 0 && tx->dataLength == ETH_ERC20_TRANSFER_LEN && !memcmp(tx->data, ETH_ERC20_SIGNATURE, ETH_ERC20_SIGNATURE_LEN)) { return TX_DATA_ERC20; } else { - return TX_DATA_PRESENT; + return TX_YES; } } @@ -375,6 +375,8 @@ void dialog_confirm_btc_summary(const btc_tx_ctx_t* tx) { uint64_t signed_amount = 0; uint64_t total_output = 0; + bool has_sighash_none = false; + for (int i = 0; i < tx->input_count; i++) { uint64_t t; memcpy(&t, tx->input_data[i].amount, sizeof(uint64_t)); @@ -382,24 +384,57 @@ void dialog_confirm_btc_summary(const btc_tx_ctx_t* tx) { if (tx->input_data[i].can_sign) { signed_amount += t; } + + if ((tx->input_data[i].sighash_flag & SIGHASH_MASK) == SIGHASH_NONE) { + has_sighash_none = true; + } } + uint64_t change = 0; + int dest_idx = -1; + for (int i = 0; i < tx->output_count; i++) { uint64_t t; memcpy(&t, tx->outputs[i].amount, sizeof(uint64_t)); total_output += t; + if (tx->output_is_change[i]) { + change += t; + } else { + if (dest_idx == -1) { + dest_idx = i; + } else { + dest_idx = -2; + } + } } - // TODO: fix labels, add basic informations on destination address + dialog_btc_amount(&ctx, TX_AMOUNT, total_input); - if (total_input == signed_amount) { - dialog_btc_amount(&ctx, TX_AMOUNT, total_input); - } else { - dialog_btc_amount(&ctx, TX_AMOUNT, total_input); + if (total_input != signed_amount) { dialog_btc_amount(&ctx, TX_SIGNED_AMOUNT, signed_amount); } + if (change) { + dialog_btc_amount(&ctx, TX_CHANGE, change); + } + dialog_btc_amount(&ctx, TX_FEE, total_input - total_output); + + + if (has_sighash_none) { + ctx.x = TH_DATA_LEFT_MARGIN; + screen_draw_text(&ctx, MESSAGE_MAX_X, MESSAGE_MAX_Y, (const uint8_t*) LSTR(TX_SIGHASH_WARNING), strlen(LSTR(TX_SIGHASH_WARNING)), false, false); + } else { + char buf[BIGNUM_STRING_LEN]; + dialog_label(&ctx, LSTR(TX_ADDRESS)); + + if (dest_idx >= 0) { + script_output_to_address(tx->outputs[dest_idx].script, tx->outputs[dest_idx].script_len, buf); + dialog_data(&ctx, buf); + } else { + dialog_data(&ctx, LSTR(TX_MULTIPLE_RECIPIENT)); + } + } } static inline void dialog_btc_sign_scheme_format(char* buf, uint32_t flag) { @@ -457,7 +492,7 @@ void dialog_confirm_btc_inouts(const btc_tx_ctx_t* tx, size_t page) { dialog_inline_data(&ctx, buf); dialog_label(&ctx, LSTR(TX_SIGNED)); - dialog_inline_data(&ctx, tx->input_data[i].can_sign ? LSTR(TX_DATA_PRESENT) : LSTR(TX_DATA_NONE)); + dialog_inline_data(&ctx, tx->input_data[i].can_sign ? LSTR(TX_YES) : LSTR(TX_NO)); i++; displayed++; @@ -477,6 +512,9 @@ void dialog_confirm_btc_inouts(const btc_tx_ctx_t* tx, size_t page) { memcpy(&t, tx->outputs[i].amount, sizeof(uint64_t)); dialog_btc_amount(&ctx, TX_AMOUNT, t); + dialog_label(&ctx, LSTR(TX_CHANGE)); + dialog_inline_data(&ctx, tx->output_is_change[i] ? LSTR(TX_YES) : LSTR(TX_NO)); + i++; displayed++; } diff --git a/app/ui/english.c b/app/ui/english.c index 9337c3a..64369b1 100644 --- a/app/ui/english.c +++ b/app/ui/english.c @@ -46,6 +46,8 @@ const char *const i18n_english_strings[] = { "To", "Amount", "Signed amount", + "Multiple recipients", + "WARNING: recipients could change! Do not sign unless you absolutely know what you are doing.", "Fee", "Signer", "Data", @@ -60,6 +62,7 @@ const char *const i18n_english_strings[] = { "NONE", "SINGLE", "ANYONECANPAY", + "Change", // MSG Confirmation "Sign message", diff --git a/app/ui/i18n.h b/app/ui/i18n.h index 9488158..845fab4 100644 --- a/app/ui/i18n.h +++ b/app/ui/i18n.h @@ -52,12 +52,14 @@ typedef enum { TX_ADDRESS, TX_AMOUNT, TX_SIGNED_AMOUNT, + TX_MULTIPLE_RECIPIENT, + TX_SIGHASH_WARNING, TX_FEE, TX_SIGNER, TX_DATA, - TX_DATA_NONE, + TX_NO, TX_DATA_ERC20, - TX_DATA_PRESENT, + TX_YES, TX_INPUT, TX_OUTPUT, TX_SIGNED, @@ -66,6 +68,7 @@ typedef enum { TX_SIGN_NONE, TX_SIGN_SINGLE, TX_SIGN_ANYONECANPAY, + TX_CHANGE, // MSG Confirmation MSG_CONFIRM_TITLE,