Skip to content

Commit

Permalink
Add special wording for self-transfers
Browse files Browse the repository at this point in the history
  • Loading branch information
bigspider committed Jun 20, 2023
1 parent 00d55dd commit b22692b
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 9 deletions.
19 changes: 14 additions & 5 deletions src/handler/sign_psbt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1378,11 +1378,20 @@ confirm_transaction(dispatcher_context_t *dc, sign_psbt_state_t *st) {
}
} else {
// Show final user validation UI
if (!ui_validate_transaction(dc, COIN_COINID_SHORT, fee)) {
SEND_SW(dc, SW_DENY);
ui_post_processing_confirm_transaction(dc, false);
return false;
};
if (st->outputs.n_external == 0) {
// All outputs are change; show the user it's a self transfer
if (!ui_validate_selftransfer(dc, COIN_COINID_SHORT, fee)) {
SEND_SW(dc, SW_DENY);
ui_post_processing_confirm_transaction(dc, false);
return false;
}
} else {
if (!ui_validate_transaction(dc, COIN_COINID_SHORT, fee)) {
SEND_SW(dc, SW_DENY);
ui_post_processing_confirm_transaction(dc, false);
return false;
}
}
}

return true;
Expand Down
11 changes: 11 additions & 0 deletions src/ui/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,17 @@ bool ui_validate_transaction(dispatcher_context_t *context, const char *coin_nam
return io_ui_process(context, true);
}

// Special case when all the outputs are change: show a "Self-transfer" screen in the flow
bool ui_validate_selftransfer(dispatcher_context_t *context, const char *coin_name, uint64_t fee) {
ui_validate_transaction_state_t *state = (ui_validate_transaction_state_t *) &g_ui_state;

format_sats_amount(coin_name, fee, state->fee);

ui_accept_selftransfer_flow();

return io_ui_process(context, true);
}

#ifdef HAVE_BAGL
bool ui_post_processing_confirm_wallet_registration(dispatcher_context_t *context, bool success) {
(void) context;
Expand Down
4 changes: 4 additions & 0 deletions src/ui/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ bool ui_validate_output(dispatcher_context_t *context,

bool ui_validate_transaction(dispatcher_context_t *context, const char *coin_name, uint64_t fee);

bool ui_validate_selftransfer(dispatcher_context_t *context, const char *coin_name, uint64_t fee);

void set_ux_flow_response(bool approved);

void ui_display_pubkey_flow(void);
Expand Down Expand Up @@ -164,6 +166,8 @@ void ui_display_output_address_amount_no_index_flow(int index);

void ui_accept_transaction_flow(void);

void ui_accept_selftransfer_flow(void);

void ui_display_transaction_prompt(const int external_outputs_total_count);

bool ui_post_processing_confirm_wallet_registration(dispatcher_context_t *context, bool success);
Expand Down
18 changes: 17 additions & 1 deletion src/ui/display_bagl.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ UX_STEP_NOCB(ux_validate_address_step,
});

UX_STEP_NOCB(ux_confirm_transaction_step, pnn, {&C_icon_eye, "Confirm", "transaction"});
UX_STEP_NOCB(ux_confirm_selftransfer_step, pnn, {&C_icon_eye, "Confirm", "self-transfer"});
UX_STEP_NOCB(ux_confirm_transaction_fees_step,
bnnn_paging,
{
Expand Down Expand Up @@ -386,7 +387,7 @@ UX_FLOW(ux_display_output_address_amount_flow,
&ux_display_reject_step);

// Finalize see the transaction fees and finally accept signing
// #1 screen: eye icon + "Confirm Transaction"
// #1 screen: eye icon + "Confirm transaction"
// #2 screen: fee amount
// #3 screen: "Accept and send", with approve button
// #4 screen: reject button
Expand All @@ -396,6 +397,17 @@ UX_FLOW(ux_accept_transaction_flow,
&ux_accept_and_send_step,
&ux_display_reject_step);

// Finalize see the transaction fees and finally accept signing
// #1 screen: eye icon + "Confirm self-transfer"
// #2 screen: fee amount
// #3 screen: "Accept and send", with approve button
// #4 screen: reject button
UX_FLOW(ux_accept_selftransfer_flow,
&ux_confirm_selftransfer_step,
&ux_confirm_transaction_fees_step,
&ux_accept_and_send_step,
&ux_display_reject_step);

void ui_display_pubkey_flow(void) {
ux_flow_init(0, ux_display_pubkey_flow, NULL);
}
Expand Down Expand Up @@ -458,4 +470,8 @@ void ui_accept_transaction_flow(void) {
ux_flow_init(0, ux_accept_transaction_flow, NULL);
}

void ui_accept_selftransfer_flow(void) {
ux_flow_init(0, ux_accept_selftransfer_flow, NULL);
}

#endif // HAVE_BAGL
45 changes: 42 additions & 3 deletions src/ui/display_nbgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ enum {
CANCEL_TOKEN = 0,
CONFIRM_TOKEN,
SILENT_CONFIRM_TOKEN,
BACK_TOKEN,
BACK_TOKEN_TRANSACTION, // for most transactions
BACK_TOKEN_SELFTRANSFER, // special case when it's a self-transfer (no external outputs)
};

extern bool G_was_processing_screen_shown;
Expand Down Expand Up @@ -91,9 +92,12 @@ static void transaction_confirm_callback(int token, uint8_t index) {
case SILENT_CONFIRM_TOKEN:
ux_flow_response(true);
break;
case BACK_TOKEN:
case BACK_TOKEN_TRANSACTION:
ui_accept_transaction_flow();
break;
case BACK_TOKEN_SELFTRANSFER:
ui_accept_selftransfer_flow();
break;
default:
PRINTF("Unhandled token : %d", token);
}
Expand Down Expand Up @@ -149,13 +153,17 @@ static void continue_callback(void) {
static void transaction_confirm(int token, uint8_t index) {
(void) index;

// If it's a self-transfer, the UX is slightly different
int backToken =
transactionContext.extOutputCount == 0 ? BACK_TOKEN_SELFTRANSFER : BACK_TOKEN_TRANSACTION;

if (token == CONFIRM_TOKEN) {
nbgl_pageNavigationInfo_t info = {.activePage = transactionContext.extOutputCount + 1,
.nbPages = transactionContext.extOutputCount + 2,
.navType = NAV_WITH_TAP,
.progressIndicator = true,
.navWithTap.backButton = true,
.navWithTap.backToken = BACK_TOKEN,
.navWithTap.backToken = backToken,
.navWithTap.nextPageText = NULL,
.navWithTap.quitText = "Reject transaction",
.quitToken = CANCEL_TOKEN,
Expand Down Expand Up @@ -204,6 +212,37 @@ void ui_accept_transaction_flow(void) {
nbgl_refresh();
}

void ui_accept_selftransfer_flow(void) {
transactionContext.tagValuePair[0].item = "Amount";
transactionContext.tagValuePair[0].value = "Self-transfer";
transactionContext.tagValuePair[1].item = "Fees";
transactionContext.tagValuePair[1].value = g_ui_state.validate_transaction.fee;

transactionContext.tagValueList.nbPairs = 2;

transactionContext.confirm = "Sign transaction\nto send Bitcoin?";
transactionContext.confirmed_status = "TRANSACTION\nSIGNED";
transactionContext.rejected_status = "Transaction rejected";

nbgl_pageNavigationInfo_t info = {.activePage = transactionContext.extOutputCount,
.nbPages = transactionContext.extOutputCount + 2,
.navType = NAV_WITH_TAP,
.progressIndicator = true,
.navWithTap.backButton = false,
.navWithTap.nextPageText = "Tap to continue",
.navWithTap.nextPageToken = CONFIRM_TOKEN,
.navWithTap.quitText = "Reject transaction",
.quitToken = CANCEL_TOKEN,
.tuneId = TUNE_TAP_CASUAL};

nbgl_pageContent_t content = {.type = TAG_VALUE_LIST,
.tagValueList.nbPairs = transactionContext.tagValueList.nbPairs,
.tagValueList.pairs = transactionContext.tagValuePair};

nbgl_pageDrawGenericContent(&transaction_confirm, &info, &content);
nbgl_refresh();
}

void ui_display_transaction_prompt(const int external_outputs_total_count) {
transactionContext.currentOutput = 0;
transactionContext.extOutputCount = external_outputs_total_count;
Expand Down
19 changes: 19 additions & 0 deletions tests/test_sign_psbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,25 @@ def test_sign_psbt_singlesig_wpkh_2to2_missing_nonwitnessutxo(client: Client):
)]


@has_automation("automations/sign_with_default_wallet_accept.json")
def test_sign_psbt_singlesig_wpkh_selftransfer(client: Client):
# The only output is a change output.
# A "self-transfer" screen should be shown before the fees.

wallet = WalletPolicy(
"",
"wpkh(@0/**)",
[
"[f5acc2fd/84'/1'/0']tpubDCtKfsNyRhULjZ9XMS4VKKtVcPdVDi8MKUbcSD9MJDyjRu1A2ND5MiipozyyspBT9bg8upEp7a8EAgFxNxXn1d7QkdbL52Ty5jiSLcxPt1P"
],
)

psbt = "cHNidP8BAHECAAAAAfcDVJxLN1tzz5vaIy2onFL/ht/OqwKm2jEWGwMNDE/cAQAAAAD9////As0qAAAAAAAAFgAUJfcXOL7SoYGoDC1n6egGa0OTD9/mtgEAAAAAABYAFDXG4N1tPISxa6iF3Kc6yGPQtZPsTTQlAAABAPYCAAAAAAEBCOcYS1aMP1uQcUKTMJbvlsZXsV4yNnVxynyMfxSX//UAAAAAFxYAFGEWho6AN6qeux0gU3BSWnK+Dw4D/f///wKfJwEAAAAAABepFG1IUtrzpUCfdyFtu46j1ZIxLX7ph0DiAQAAAAAAFgAU4e5IJz0XxNe96ANYDugMQ34E0/cCRzBEAiB1b84pX0QaOUrvCdDxKeB+idM6wYKTLGmqnUU/tL8/lQIgbSinpq4jBlo+SIGyh8XNVrWAeMlKBNmoLenKOBugKzcBIQKXsd8NwO+9naIfeI3nkgYjg6g3QZarGTRDs7SNVZfGPJBJJAABAR9A4gEAAAAAABYAFOHuSCc9F8TXvegDWA7oDEN+BNP3IgYCgffBheEUZI8iAFFfv7b+HNM7j4jolv6lj5/n3j68h3kY9azC/VQAAIABAACAAAAAgAAAAAAHAAAAACICAzQZjNnkwXFEhm1F6oC2nk1ADqH6t/RHBAOblLA4tV5BGPWswv1UAACAAQAAgAAAAIABAAAAEgAAAAAiAgJxtbd5rYcIOFh3l7z28MeuxavnanCdck9I0uJs+HTwoBj1rML9VAAAgAEAAIAAAACAAQAAAAAAAAAA"
result = client.sign_psbt(psbt, wallet, None)

assert len(result) == 1


# def test_sign_psbt_legacy(client: Client):
# # legacy address
# # PSBT for a legacy 1-input 1-output spend
Expand Down

0 comments on commit b22692b

Please sign in to comment.