UI bypass
The goal of the Exchange application is to allow the user to perform a fully trusted SWAP through a single screen UI review.
The Exchange application handles the trust checking and the UI, the FROM coin application handles the final payment. This final payment needs to be validated without UI call as long as all conditions are strictly met.
Please refer to the sequence diagram if you want to see the process flow in more details.
The UI bypass on the coin application need to abide by the following rules:
- The bypass is used only when started by Exchange.
- The bypass is only used for a single type of simple transaction.
- The bypass is only used if the destination strictly matches.
- The bypass is only used if the amount strictly matches.
- The bypass is only used if the fees strictly matches.
If a transaction received in the SWAP context does not match the requirements, it needs to be rejected without UI prompt. The Exchange application will handle the refusal screen display.
Here is an example of the high level detection of the UI bypass.
app-solana/src/handle_sign_message.c
void handle_sign_message_ui(volatile unsigned int *flags) {
// Display the transaction summary
SummaryItemKind_t summary_step_kinds[MAX_TRANSACTION_SUMMARY_ITEMS];
size_t num_summary_steps = 0;
if (transaction_summary_finalize(summary_step_kinds, &num_summary_steps) == 0) {
// If we are in swap context, do not redisplay the message data
// Instead, ensure they are identical with what was previously displayed
if (G_called_from_swap) {
if (G_swap_response_ready) {
// Safety against trying to make the app sign multiple TX
// This code should never be triggered as the app is supposed to exit after
// sending the signed transaction
PRINTF("Safety against double signing triggered\n");
os_sched_exit(-1);
} else {
// We will quit the app after this transaction, whether it succeeds or fails
PRINTF("Swap response is ready, the app will quit after the next send\n");
G_swap_response_ready = true;
}
if (check_swap_validity(summary_step_kinds, num_summary_steps)) {
PRINTF("Valid swap transaction received, signing and replying it\n");
sendResponse(set_result_sign_message(), ApduReplySuccess, false);
} else {
PRINTF("Refuse to sign an incorrect Swap transaction\n");
sendResponse(0, ApduReplySolanaSummaryFinalizeFailed, false);
}
} else {
// We have been started from the dashboard, prompt the UI to the user as usual
start_sign_tx_ui(num_summary_steps);
}
} else {
THROW(ApduReplySolanaSummaryFinalizeFailed);
}
*flags |= IO_ASYNCH_REPLY;
}
The content of the check_swap_validity()
function can also be found in the linked file for more information.