feat(legacy): implement amount_unit for SignTx

pull/1426/head
Pavol Rusnak 3 years ago committed by Tomas Susanka
parent 7f0e939359
commit 1d3166017d

@ -26,7 +26,7 @@ const CoinInfo coins[COINS_COUNT] = {
% for c in supported_on("trezor1", bitcoin): % for c in supported_on("trezor1", bitcoin):
{ {
.coin_name = ${c_str(c.coin_name)}, .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)}, .maxfee_kb = ${c_int(c.maxfee_kb)},
.signed_message_header = ${signed_message_header(c.signed_message_header)}, .signed_message_header = ${signed_message_header(c.signed_message_header)},
.has_segwit = ${c_bool(c.segwit)}, .has_segwit = ${c_bool(c.segwit)},

@ -92,18 +92,18 @@ static const char *address_n_str(const uint32_t *address_n,
const char *abbr = 0; const char *abbr = 0;
if (native_segwit) { if (native_segwit) {
if (coin && coin->has_segwit && coin->bech32_prefix) { if (coin && coin->has_segwit && coin->bech32_prefix) {
abbr = coin->coin_shortcut + 1; abbr = coin->coin_shortcut;
} }
} else if (p2sh_segwit) { } else if (p2sh_segwit) {
if (coin && coin->has_segwit) { if (coin && coin->has_segwit) {
abbr = coin->coin_shortcut + 1; abbr = coin->coin_shortcut;
} }
} else { } else {
if (coin) { if (coin) {
if (coin->has_segwit) { if (coin->has_segwit) {
legacy = true; legacy = true;
} }
abbr = coin->coin_shortcut + 1; abbr = coin->coin_shortcut;
#if !BITCOIN_ONLY #if !BITCOIN_ONLY
} else { } else {
abbr = slip44_extras(address_n[1]); abbr = slip44_extras(address_n[1]);
@ -346,10 +346,51 @@ static void render_address_dialog(const CoinInfo *coin, const char *address,
oledRefresh(); 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}; char str_out[32 + 3] = {0};
bn_format_uint64(out->amount, NULL, coin->coin_shortcut, coin->decimals, 0, format_coin_amount(out->amount, NULL, coin, amount_unit, str_out,
false, str_out, sizeof(str_out) - 3); sizeof(str_out) - 3);
strlcat(str_out, " to", sizeof(str_out)); strlcat(str_out, " to", sizeof(str_out));
const char *address = out->address; const char *address = out->address;
const char *extra_line = const char *extra_line =
@ -423,9 +464,9 @@ void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) {
NULL); NULL);
} }
static bool formatAmountDifference(const CoinInfo *coin, uint64_t amount1, static bool formatAmountDifference(const CoinInfo *coin, AmountUnit amount_unit,
uint64_t amount2, char *output, uint64_t amount1, uint64_t amount2,
size_t output_length) { char *output, size_t output_length) {
uint64_t abs_diff = 0; uint64_t abs_diff = 0;
const char *sign = NULL; const char *sign = NULL;
if (amount1 >= amount2) { if (amount1 >= amount2) {
@ -435,17 +476,20 @@ static bool formatAmountDifference(const CoinInfo *coin, uint64_t amount1,
sign = "-"; sign = "-";
} }
return bn_format_uint64(abs_diff, sign, coin->coin_shortcut, coin->decimals, return format_coin_amount(abs_diff, sign, coin, amount_unit, output,
0, false, output, output_length) != 0; output_length) != 0;
} }
void layoutConfirmTx(const CoinInfo *coin, uint64_t total_in, void layoutConfirmTx(const CoinInfo *coin, AmountUnit amount_unit,
uint64_t total_out, uint64_t change_out) { uint64_t total_in, uint64_t total_out,
uint64_t change_out) {
char str_out[32] = {0}; 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}; 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, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Really send"), str_out, _("from your wallet?"), _("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); description, str[0], str[1], str[2], str[3], NULL);
} }
void layoutConfirmModifyFee(const CoinInfo *coin, uint64_t fee_old, void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit,
uint64_t fee_new) { uint64_t fee_old, uint64_t fee_new) {
char str_fee_change[32] = {0}; char str_fee_change[32] = {0};
char str_fee_new[32] = {0}; char str_fee_new[32] = {0};
char *question = NULL; char *question = NULL;
@ -472,21 +516,21 @@ void layoutConfirmModifyFee(const CoinInfo *coin, uint64_t fee_old,
question = _("Decrease your fee by:"); question = _("Decrease your fee by:");
fee_change = fee_old - fee_new; fee_change = fee_old - fee_new;
} }
bn_format_uint64(fee_change, NULL, coin->coin_shortcut, coin->decimals, 0, format_coin_amount(fee_change, NULL, coin, amount_unit, str_fee_change,
false, str_fee_change, sizeof(str_fee_change)); sizeof(str_fee_change));
bn_format_uint64(fee_new, NULL, coin->coin_shortcut, coin->decimals, 0, false, format_coin_amount(fee_new, NULL, coin, amount_unit, str_fee_new,
str_fee_new, sizeof(str_fee_new)); sizeof(str_fee_new));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
question, str_fee_change, NULL, _("Transaction fee:"), question, str_fee_change, NULL, _("Transaction fee:"),
str_fee_new, NULL); 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}; char str_fee[32] = {0};
bn_format_uint64(fee, NULL, coin->coin_shortcut, coin->decimals, 0, false, format_coin_amount(fee, NULL, coin, amount_unit, str_fee, sizeof(str_fee));
str_fee, sizeof(str_fee));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Fee"), str_fee, _("is unexpectedly high."), NULL, _("Fee"), str_fee, _("is unexpectedly high."), NULL,
_("Send anyway?"), NULL); _("Send anyway?"), NULL);

@ -46,15 +46,18 @@ void layoutProgressSwipe(const char *desc, int permil);
void layoutScreensaver(void); void layoutScreensaver(void);
void layoutHome(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 layoutConfirmOmni(const uint8_t *data, uint32_t size);
void layoutConfirmOpReturn(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, void layoutConfirmTx(const CoinInfo *coin, AmountUnit amount_unit,
uint64_t total_out, uint64_t change_out); uint64_t total_in, uint64_t total_out,
uint64_t change_out);
void layoutConfirmReplacement(const char *description, uint8_t txid[32]); void layoutConfirmReplacement(const char *description, uint8_t txid[32]);
void layoutConfirmModifyFee(const CoinInfo *coin, uint64_t fee_old, void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit,
uint64_t fee_new); uint64_t fee_old, uint64_t fee_new);
void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); void layoutFeeOverThreshold(const CoinInfo *coin, AmountUnit amount_unit,
uint64_t fee);
void layoutChangeCountOverThreshold(uint32_t change_count); void layoutChangeCountOverThreshold(uint32_t change_count);
void layoutConfirmNondefaultLockTime(uint32_t lock_time, void layoutConfirmNondefaultLockTime(uint32_t lock_time,
bool lock_time_disabled); bool lock_time_disabled);

@ -32,6 +32,7 @@
static uint32_t change_count; static uint32_t change_count;
static const CoinInfo *coin; static const CoinInfo *coin;
static AmountUnit amount_unit;
static CONFIDENTIAL HDNode root; static CONFIDENTIAL HDNode root;
static CONFIDENTIAL HDNode node; static CONFIDENTIAL HDNode node;
static bool signing = false; 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, void signing_init(const SignTx *msg, const CoinInfo *_coin,
const HDNode *_root) { const HDNode *_root) {
coin = _coin; coin = _coin;
amount_unit = msg->has_amount_unit ? msg->amount_unit : AmountUnit_BITCOIN;
memcpy(&root, _root, sizeof(HDNode)); memcpy(&root, _root, sizeof(HDNode));
if (!tx_info_init(&info, msg->inputs_count, msg->outputs_count, msg->version, 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 // Skip confirmation of change-outputs and skip output confirmation altogether
// in replacement transactions. // in replacement transactions.
bool skip_confirm = is_change || is_replacement; 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) { if (!skip_confirm) {
layoutProgress(_("Signing transaction"), progress); 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) { static bool signing_check_orig_output(TxOutputType *orig_output) {
// Compute scriptPubKey. // Compute scriptPubKey.
TxOutputBinType orig_bin_output; 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, fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to compile output")); _("Failed to compile output"));
signing_abort(); signing_abort();
@ -1480,7 +1484,7 @@ static bool signing_confirm_tx(void) {
if (total_out <= total_in) { if (total_out <= total_in) {
fee = total_in - total_out; fee = total_in - total_out;
if (fee > ((uint64_t)tx_weight * coin->maxfee_kb) / 4000) { if (fee > ((uint64_t)tx_weight * coin->maxfee_kb) / 4000) {
layoutFeeOverThreshold(coin, fee); layoutFeeOverThreshold(coin, amount_unit, fee);
if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold,
false)) { false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
@ -1565,7 +1569,7 @@ static bool signing_confirm_tx(void) {
// Fee modification. // Fee modification.
if (fee != orig_fee) { if (fee != orig_fee) {
layoutConfirmModifyFee(coin, orig_fee, fee); layoutConfirmModifyFee(coin, amount_unit, orig_fee, fee);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
signing_abort(); signing_abort();
@ -1586,7 +1590,7 @@ static bool signing_confirm_tx(void) {
} }
// last confirmation // 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)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
signing_abort(); signing_abort();
@ -2431,7 +2435,8 @@ void signing_txack(TransactionType *tx) {
progress = 500 + ((signatures * progress_step + progress = 500 + ((signatures * progress_step +
(info.inputs_count + idx2) * progress_meta_step) >> (info.inputs_count + idx2) * progress_meta_step) >>
PROGRESS_PRECISION); 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, fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to compile output")); _("Failed to compile output"));
signing_abort(); signing_abort();
@ -2573,7 +2578,8 @@ void signing_txack(TransactionType *tx) {
if (!signing_validate_output(&tx->outputs[0])) { if (!signing_validate_output(&tx->outputs[0])) {
return; 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, fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to compile output")); _("Failed to compile output"));
signing_abort(); signing_abort();

@ -191,8 +191,9 @@ bool compute_address(const CoinInfo *coin, InputScriptType script_type,
return 1; return 1;
} }
int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, int compile_output(const CoinInfo *coin, AmountUnit amount_unit,
TxOutputBinType *out, bool needs_confirm) { const HDNode *root, TxOutputType *in, TxOutputBinType *out,
bool needs_confirm) {
memzero(out, sizeof(TxOutputBinType)); memzero(out, sizeof(TxOutputBinType));
out->amount = in->amount; out->amount = in->amount;
out->decred_script_version = DECRED_SCRIPT_VERSION; 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) { if (needs_confirm) {
layoutConfirmOutput(coin, in); layoutConfirmOutput(coin, amount_unit, in);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return -1; // user aborted return -1; // user aborted
} }

@ -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, uint32_t serialize_script_multisig(const CoinInfo *coin,
const MultisigRedeemScriptType *multisig, const MultisigRedeemScriptType *multisig,
uint8_t sighash, uint8_t *out); uint8_t sighash, uint8_t *out);
int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, int compile_output(const CoinInfo *coin, AmountUnit amount_unit,
TxOutputBinType *out, bool needs_confirm); const HDNode *root, TxOutputType *in, TxOutputBinType *out,
bool needs_confirm);
void tx_input_check_hash(Hasher *hasher, const TxInputType *input); void tx_input_check_hash(Hasher *hasher, const TxInputType *input);
uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input);

Loading…
Cancel
Save