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-boilerplate/src/handler/sign_tx.c

#ifdef HAVE_SWAP
static int check_and_sign_swap_tx(transaction_t *tx) {
    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");
        // This boolean will make the io_send_sw family instant reply +
        // return to exchange
        G_swap_response_ready = true;
    }
    if (swap_check_validity(tx->value, tx->fee, tx->to)) {
        PRINTF("Swap response validated\n");
        validate_transaction(true);
    }
    // Unreachable because swap_check_validity() returns an error to exchange app OR
    // validate_transaction() returns a success to exchange
    return 0;
}
#endif  // HAVE_SWAP

Here is the function swap_check_validity() called for checking the content of the received TX against the data validated in the Exchange application,

app-boilerplate/src/swap/handle_swap_sign_transaction.c

/* Check if the Tx to sign have the same parameters as the ones previously validated */
bool swap_check_validity(uint64_t amount, uint64_t fee, const uint8_t* destination) {
    PRINTF("Inside swap_check_validity\n");

    if (!G_swap_validated.initialized) {
        PRINTF("Swap structure is not initialized\n");
        send_swap_error_simple(SW_SWAP_FAIL, SWAP_EC_ERROR_GENERIC, SWAP_ERROR_CODE);
        // unreachable
        os_sched_exit(0);
    }

    if (G_swap_validated.amount != amount) {
        PRINTF("Amount does not match, promised %lld, received %lld\n",
               G_swap_validated.amount,
               amount);
        send_swap_error_simple(SW_SWAP_FAIL, SWAP_EC_ERROR_WRONG_AMOUNT, SWAP_ERROR_CODE);
        // unreachable
        os_sched_exit(0);
    } else {
        PRINTF("Amounts match \n");
    }

    if (G_swap_validated.fee != fee) {
        PRINTF("Fee does not match, promised %lld, received %lld\n", G_swap_validated.fee, fee);
        send_swap_error_simple(SW_SWAP_FAIL, SWAP_EC_ERROR_WRONG_FEES, SWAP_ERROR_CODE);
        // unreachable
        os_sched_exit(0);
    } else {
        PRINTF("Fees match \n");
    }

    char to[ADDRESS_LEN * 2 + 1] = {0};
    format_hex(destination, ADDRESS_LEN, to, sizeof(to));
    if (strcmp(G_swap_validated.recipient, to) != 0) {
        PRINTF("Destination does not match\n");
        PRINTF("Validated: %s\n", G_swap_validated.recipient);
        PRINTF("Received: %s \n", to);
        send_swap_error_simple(SW_SWAP_FAIL, SWAP_EC_ERROR_WRONG_DESTINATION, SWAP_ERROR_CODE);
        // unreachable
        os_sched_exit(0);
    } else {
        PRINTF("Destination is valid\n");
    }
    return true;
}

The Boilerplate does not have tokens, as a result there is no check on the type of currency signed. If your application is able to handle multiple currencies, this is a check that you must add.