From 1d3166017d2de35b5e62113852568b2e3c81f01b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 Jan 2021 16:49:33 +0100 Subject: [PATCH] feat(legacy): implement amount_unit for SignTx --- legacy/firmware/coin_info.c.mako | 2 +- legacy/firmware/layout2.c | 92 +++++++++++++++++++++++--------- legacy/firmware/layout2.h | 15 +++--- legacy/firmware/signing.c | 20 ++++--- legacy/firmware/transaction.c | 7 +-- legacy/firmware/transaction.h | 5 +- 6 files changed, 98 insertions(+), 43 deletions(-) diff --git a/legacy/firmware/coin_info.c.mako b/legacy/firmware/coin_info.c.mako index 56fe9e3f1..bb3a67f68 100644 --- a/legacy/firmware/coin_info.c.mako +++ b/legacy/firmware/coin_info.c.mako @@ -26,7 +26,7 @@ const CoinInfo coins[COINS_COUNT] = { % for c in supported_on("trezor1", bitcoin): { .coin_name = ${c_str(c.coin_name)}, - .coin_shortcut = ${c_str(" " + c.coin_shortcut)}, + .coin_shortcut = ${c_str(c.coin_shortcut)}, .maxfee_kb = ${c_int(c.maxfee_kb)}, .signed_message_header = ${signed_message_header(c.signed_message_header)}, .has_segwit = ${c_bool(c.segwit)}, diff --git a/legacy/firmware/layout2.c b/legacy/firmware/layout2.c index 96a918488..352ebef34 100644 --- a/legacy/firmware/layout2.c +++ b/legacy/firmware/layout2.c @@ -92,18 +92,18 @@ static const char *address_n_str(const uint32_t *address_n, const char *abbr = 0; if (native_segwit) { if (coin && coin->has_segwit && coin->bech32_prefix) { - abbr = coin->coin_shortcut + 1; + abbr = coin->coin_shortcut; } } else if (p2sh_segwit) { if (coin && coin->has_segwit) { - abbr = coin->coin_shortcut + 1; + abbr = coin->coin_shortcut; } } else { if (coin) { if (coin->has_segwit) { legacy = true; } - abbr = coin->coin_shortcut + 1; + abbr = coin->coin_shortcut; #if !BITCOIN_ONLY } else { abbr = slip44_extras(address_n[1]); @@ -346,10 +346,51 @@ static void render_address_dialog(const CoinInfo *coin, const char *address, oledRefresh(); } -void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) { +static size_t format_coin_amount(uint64_t amount, const char *prefix, + const CoinInfo *coin, AmountUnit amount_unit, + char *output, size_t output_len) { + // " " + (optional "m"/u") + shortcut + ending zero -> 16 should suffice + char suffix[16]; + memzero(suffix, sizeof(suffix)); + suffix[0] = ' '; + uint32_t decimals = coin->decimals; + switch (amount_unit) { + case AmountUnit_SATOSHI: + decimals = 0; + strlcpy(suffix + 1, "sat ", sizeof(suffix) - 1); + strlcpy(suffix + 5, coin->coin_shortcut, sizeof(suffix) - 5); + break; + case AmountUnit_MILLIBITCOIN: + if (decimals >= 6) { + decimals -= 6; + suffix[1] = 'u'; + strlcpy(suffix + 2, coin->coin_shortcut, sizeof(suffix) - 2); + } else { + strlcpy(suffix + 1, coin->coin_shortcut, sizeof(suffix) - 1); + } + break; + case AmountUnit_MICROBITCOIN: + if (decimals >= 3) { + decimals -= 3; + suffix[1] = 'm'; + strlcpy(suffix + 2, coin->coin_shortcut, sizeof(suffix) - 2); + } else { + strlcpy(suffix + 1, coin->coin_shortcut, sizeof(suffix) - 1); + } + break; + default: // AmountUnit_BITCOIN + strlcpy(suffix + 1, coin->coin_shortcut, sizeof(suffix) - 1); + break; + } + return bn_format_uint64(amount, prefix, suffix, decimals, 0, false, output, + output_len); +} + +void layoutConfirmOutput(const CoinInfo *coin, AmountUnit amount_unit, + const TxOutputType *out) { char str_out[32 + 3] = {0}; - bn_format_uint64(out->amount, NULL, coin->coin_shortcut, coin->decimals, 0, - false, str_out, sizeof(str_out) - 3); + format_coin_amount(out->amount, NULL, coin, amount_unit, str_out, + sizeof(str_out) - 3); strlcat(str_out, " to", sizeof(str_out)); const char *address = out->address; const char *extra_line = @@ -423,9 +464,9 @@ void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) { NULL); } -static bool formatAmountDifference(const CoinInfo *coin, uint64_t amount1, - uint64_t amount2, char *output, - size_t output_length) { +static bool formatAmountDifference(const CoinInfo *coin, AmountUnit amount_unit, + uint64_t amount1, uint64_t amount2, + char *output, size_t output_length) { uint64_t abs_diff = 0; const char *sign = NULL; if (amount1 >= amount2) { @@ -435,17 +476,20 @@ static bool formatAmountDifference(const CoinInfo *coin, uint64_t amount1, sign = "-"; } - return bn_format_uint64(abs_diff, sign, coin->coin_shortcut, coin->decimals, - 0, false, output, output_length) != 0; + return format_coin_amount(abs_diff, sign, coin, amount_unit, output, + output_length) != 0; } -void layoutConfirmTx(const CoinInfo *coin, uint64_t total_in, - uint64_t total_out, uint64_t change_out) { +void layoutConfirmTx(const CoinInfo *coin, AmountUnit amount_unit, + uint64_t total_in, uint64_t total_out, + uint64_t change_out) { char str_out[32] = {0}; - formatAmountDifference(coin, total_in, change_out, str_out, sizeof(str_out)); + formatAmountDifference(coin, amount_unit, total_in, change_out, str_out, + sizeof(str_out)); char str_fee[32] = {0}; - formatAmountDifference(coin, total_in, total_out, str_fee, sizeof(str_fee)); + formatAmountDifference(coin, amount_unit, total_in, total_out, str_fee, + sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Really send"), str_out, _("from your wallet?"), @@ -458,8 +502,8 @@ void layoutConfirmReplacement(const char *description, uint8_t txid[32]) { description, str[0], str[1], str[2], str[3], NULL); } -void layoutConfirmModifyFee(const CoinInfo *coin, uint64_t fee_old, - uint64_t fee_new) { +void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit, + uint64_t fee_old, uint64_t fee_new) { char str_fee_change[32] = {0}; char str_fee_new[32] = {0}; char *question = NULL; @@ -472,21 +516,21 @@ void layoutConfirmModifyFee(const CoinInfo *coin, uint64_t fee_old, question = _("Decrease your fee by:"); fee_change = fee_old - fee_new; } - bn_format_uint64(fee_change, NULL, coin->coin_shortcut, coin->decimals, 0, - false, str_fee_change, sizeof(str_fee_change)); + format_coin_amount(fee_change, NULL, coin, amount_unit, str_fee_change, + sizeof(str_fee_change)); - bn_format_uint64(fee_new, NULL, coin->coin_shortcut, coin->decimals, 0, false, - str_fee_new, sizeof(str_fee_new)); + format_coin_amount(fee_new, NULL, coin, amount_unit, str_fee_new, + sizeof(str_fee_new)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, question, str_fee_change, NULL, _("Transaction fee:"), str_fee_new, NULL); } -void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) { +void layoutFeeOverThreshold(const CoinInfo *coin, AmountUnit amount_unit, + uint64_t fee) { char str_fee[32] = {0}; - bn_format_uint64(fee, NULL, coin->coin_shortcut, coin->decimals, 0, false, - str_fee, sizeof(str_fee)); + format_coin_amount(fee, NULL, coin, amount_unit, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Fee"), str_fee, _("is unexpectedly high."), NULL, _("Send anyway?"), NULL); diff --git a/legacy/firmware/layout2.h b/legacy/firmware/layout2.h index 816b7283f..7f02a259a 100644 --- a/legacy/firmware/layout2.h +++ b/legacy/firmware/layout2.h @@ -46,15 +46,18 @@ void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); void layoutHome(void); -void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); +void layoutConfirmOutput(const CoinInfo *coin, AmountUnit amount_unit, + const TxOutputType *out); void layoutConfirmOmni(const uint8_t *data, uint32_t size); void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); -void layoutConfirmTx(const CoinInfo *coin, uint64_t total_in, - uint64_t total_out, uint64_t change_out); +void layoutConfirmTx(const CoinInfo *coin, AmountUnit amount_unit, + uint64_t total_in, uint64_t total_out, + uint64_t change_out); void layoutConfirmReplacement(const char *description, uint8_t txid[32]); -void layoutConfirmModifyFee(const CoinInfo *coin, uint64_t fee_old, - uint64_t fee_new); -void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); +void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit, + uint64_t fee_old, uint64_t fee_new); +void layoutFeeOverThreshold(const CoinInfo *coin, AmountUnit amount_unit, + uint64_t fee); void layoutChangeCountOverThreshold(uint32_t change_count); void layoutConfirmNondefaultLockTime(uint32_t lock_time, bool lock_time_disabled); diff --git a/legacy/firmware/signing.c b/legacy/firmware/signing.c index ce72eff69..5081ad0d9 100644 --- a/legacy/firmware/signing.c +++ b/legacy/firmware/signing.c @@ -32,6 +32,7 @@ static uint32_t change_count; static const CoinInfo *coin; +static AmountUnit amount_unit; static CONFIDENTIAL HDNode root; static CONFIDENTIAL HDNode node; static bool signing = false; @@ -799,6 +800,7 @@ static bool tx_info_init(TxInfo *tx_info, uint32_t inputs_count, void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) { coin = _coin; + amount_unit = msg->has_amount_unit ? msg->amount_unit : AmountUnit_BITCOIN; memcpy(&root, _root, sizeof(HDNode)); if (!tx_info_init(&info, msg->inputs_count, msg->outputs_count, msg->version, @@ -1229,7 +1231,8 @@ static bool signing_check_output(TxOutputType *txoutput) { // Skip confirmation of change-outputs and skip output confirmation altogether // in replacement transactions. bool skip_confirm = is_change || is_replacement; - int co = compile_output(coin, &root, txoutput, &bin_output, !skip_confirm); + int co = compile_output(coin, amount_unit, &root, txoutput, &bin_output, + !skip_confirm); if (!skip_confirm) { layoutProgress(_("Signing transaction"), progress); } @@ -1375,7 +1378,8 @@ static bool signing_check_orig_input(TxInputType *orig_input) { static bool signing_check_orig_output(TxOutputType *orig_output) { // Compute scriptPubKey. TxOutputBinType orig_bin_output; - if (compile_output(coin, &root, orig_output, &orig_bin_output, false) <= 0) { + if (compile_output(coin, amount_unit, &root, orig_output, &orig_bin_output, + false) <= 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); @@ -1480,7 +1484,7 @@ static bool signing_confirm_tx(void) { if (total_out <= total_in) { fee = total_in - total_out; if (fee > ((uint64_t)tx_weight * coin->maxfee_kb) / 4000) { - layoutFeeOverThreshold(coin, fee); + layoutFeeOverThreshold(coin, amount_unit, fee); if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); @@ -1565,7 +1569,7 @@ static bool signing_confirm_tx(void) { // Fee modification. if (fee != orig_fee) { - layoutConfirmModifyFee(coin, orig_fee, fee); + layoutConfirmModifyFee(coin, amount_unit, orig_fee, fee); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); @@ -1586,7 +1590,7 @@ static bool signing_confirm_tx(void) { } // last confirmation - layoutConfirmTx(coin, total_in, total_out, change_out); + layoutConfirmTx(coin, amount_unit, total_in, total_out, change_out); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); @@ -2431,7 +2435,8 @@ void signing_txack(TransactionType *tx) { progress = 500 + ((signatures * progress_step + (info.inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); - if (compile_output(coin, &root, tx->outputs, &bin_output, false) <= 0) { + if (compile_output(coin, amount_unit, &root, tx->outputs, &bin_output, + false) <= 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); @@ -2573,7 +2578,8 @@ void signing_txack(TransactionType *tx) { if (!signing_validate_output(&tx->outputs[0])) { return; } - if (compile_output(coin, &root, tx->outputs, &bin_output, false) <= 0) { + if (compile_output(coin, amount_unit, &root, tx->outputs, &bin_output, + false) <= 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); diff --git a/legacy/firmware/transaction.c b/legacy/firmware/transaction.c index 8423ef3e1..e6cc22d41 100644 --- a/legacy/firmware/transaction.c +++ b/legacy/firmware/transaction.c @@ -191,8 +191,9 @@ bool compute_address(const CoinInfo *coin, InputScriptType script_type, return 1; } -int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, - TxOutputBinType *out, bool needs_confirm) { +int compile_output(const CoinInfo *coin, AmountUnit amount_unit, + const HDNode *root, TxOutputType *in, TxOutputBinType *out, + bool needs_confirm) { memzero(out, sizeof(TxOutputBinType)); out->amount = in->amount; out->decred_script_version = DECRED_SCRIPT_VERSION; @@ -328,7 +329,7 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, } if (needs_confirm) { - layoutConfirmOutput(coin, in); + layoutConfirmOutput(coin, amount_unit, in); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return -1; // user aborted } diff --git a/legacy/firmware/transaction.h b/legacy/firmware/transaction.h index 81783d1bc..493f51568 100644 --- a/legacy/firmware/transaction.h +++ b/legacy/firmware/transaction.h @@ -72,8 +72,9 @@ uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); -int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, - TxOutputBinType *out, bool needs_confirm); +int compile_output(const CoinInfo *coin, AmountUnit amount_unit, + const HDNode *root, TxOutputType *in, TxOutputBinType *out, + bool needs_confirm); void tx_input_check_hash(Hasher *hasher, const TxInputType *input); uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input);