From 8708faa590d9dbfdf5a3c10800f6b3d84550e27e Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Wed, 19 Apr 2023 15:39:21 +0200 Subject: [PATCH] Remove context parameter being passed everywhere Remove useless features like send function and handler callbacks Factorize validation globals in global context --- .../reusable_swap_functional_tests.yml | 2 +- src/check_asset_in.c | 118 ++++--- src/check_asset_in.h | 9 +- src/check_partner.c | 19 +- src/check_partner.h | 9 +- src/check_payout_address.c | 61 ++-- src/check_payout_address.h | 9 +- src/check_refund_address.c | 97 +++--- src/check_refund_address.h | 9 +- src/check_tx_signature.c | 32 +- src/check_tx_signature.h | 9 +- src/command_dispatcher.c | 83 ++--- src/command_dispatcher.h | 9 +- src/currency_lib_calls.c | 15 +- src/currency_lib_calls.h | 14 +- src/get_version_handler.c | 7 +- src/get_version_handler.h | 9 +- src/globals.h | 72 +++++ src/init.c | 12 +- src/init.h | 9 +- src/io.c | 180 +++++++++++ src/io.h | 32 ++ src/main.c | 89 +----- src/menu.c | 289 ------------------ src/menu.h | 22 -- src/parse_coin_config.c | 2 +- src/process_transaction.c | 165 +++++----- src/process_transaction.h | 9 +- src/reply_error.c | 10 - src/reply_error.h | 12 - src/send_function.h | 6 - src/set_partner_key.c | 43 +-- src/set_partner_key.h | 9 +- src/start_new_transaction.c | 34 +-- src/start_new_transaction.h | 9 +- src/start_signing_transaction.c | 44 +-- src/start_signing_transaction.h | 10 +- src/swap_app_context.h | 61 ---- src/ui/menu.h | 3 + src/ui/menu_bagl.c | 43 +++ src/ui/validate_transaction.h | 3 + src/ui/validate_transaction_bagl.c | 110 +++++++ src/unexpected_command.c | 9 - src/unexpected_command.h | 10 - 44 files changed, 855 insertions(+), 953 deletions(-) create mode 100644 src/io.c create mode 100644 src/io.h delete mode 100644 src/menu.c delete mode 100644 src/menu.h delete mode 100644 src/reply_error.c delete mode 100644 src/reply_error.h delete mode 100644 src/send_function.h delete mode 100644 src/swap_app_context.h create mode 100644 src/ui/menu.h create mode 100644 src/ui/menu_bagl.c create mode 100644 src/ui/validate_transaction.h create mode 100644 src/ui/validate_transaction_bagl.c delete mode 100644 src/unexpected_command.c delete mode 100644 src/unexpected_command.h diff --git a/.github/workflows/reusable_swap_functional_tests.yml b/.github/workflows/reusable_swap_functional_tests.yml index d3fd6d7b..b1509eab 100644 --- a/.github/workflows/reusable_swap_functional_tests.yml +++ b/.github/workflows/reusable_swap_functional_tests.yml @@ -41,7 +41,7 @@ on: type: string branch_for_solana: required: false - default: "wip/fbeutin/swap_rebase_post_refacto" + default: "develop" type: string jobs: diff --git a/src/check_asset_in.c b/src/check_asset_in.c index 4fd41f0e..985f0379 100644 --- a/src/check_asset_in.c +++ b/src/check_asset_in.c @@ -5,14 +5,15 @@ #include "swap_errors.h" #include "globals.h" #include "currency_lib_calls.h" -#include "reply_error.h" +#include "io.h" #include "parse_check_address_message.h" #include "parse_coin_config.h" #include "printable_amount.h" +#include "validate_transaction.h" #include "menu.h" #include "pb_structs.h" -int check_asset_in(swap_app_context_t *ctx, const command_t *cmd, SendFunction send) { +int check_asset_in(const command_t *cmd) { static buf_t config; static buf_t der; static buf_t address_parameters; @@ -22,14 +23,14 @@ int check_asset_in(swap_app_context_t *ctx, const command_t *cmd, SendFunction s if (parse_check_address_message(cmd, &config, &der, &address_parameters) == 0) { PRINTF("Error: Can't parse CHECK_ASSET_IN command\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } - static unsigned char hash[CURVE_SIZE_BYTES]; + uint8_t hash[CURVE_SIZE_BYTES]; cx_hash_sha256(config.bytes, config.size, hash, CURVE_SIZE_BYTES); - if (cx_ecdsa_verify(&ctx->ledger_public_key, + if (cx_ecdsa_verify(&G_swap_ctx.ledger_public_key, CX_LAST, CX_SHA256, hash, @@ -38,110 +39,101 @@ int check_asset_in(swap_app_context_t *ctx, const command_t *cmd, SendFunction s der.size) == 0) { PRINTF("Error: Fail to verify signature of coin config\n"); - return reply_error(ctx, SIGN_VERIFICATION_FAIL, send); + return reply_error(SIGN_VERIFICATION_FAIL); } - if (parse_coin_config(&config, &ticker, &application_name, &ctx->payin_coin_config) == 0) { + if (parse_coin_config(&config, &ticker, &application_name, &G_swap_ctx.payin_coin_config) == + 0) { PRINTF("Error: Can't parse CRYPTO coin config command\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } // Check that given ticker match current context - char *in_currency = (ctx->subcommand == SELL ? ctx->sell_transaction.in_currency - : ctx->fund_transaction.in_currency); + char *in_currency = (G_swap_ctx.subcommand == SELL ? G_swap_ctx.sell_transaction.in_currency + : G_swap_ctx.fund_transaction.in_currency); if (strlen(in_currency) != ticker.size || strncmp(in_currency, (const char *) ticker.bytes, ticker.size) != 0) { PRINTF("Error: currency ticker doesn't match configuration ticker\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } PRINTF("Coin configuration parsed: OK\n"); // creating 0-terminated application name - memset(ctx->payin_binary_name, 0, sizeof(ctx->payin_binary_name)); - memcpy(ctx->payin_binary_name, application_name.bytes, application_name.size); + memset(G_swap_ctx.payin_binary_name, 0, sizeof(G_swap_ctx.payin_binary_name)); + memcpy(G_swap_ctx.payin_binary_name, application_name.bytes, application_name.size); PRINTF("PATH inside the SWAP = %.*H\n", address_parameters.size, address_parameters.bytes); - static char in_printable_amount[MAX_PRINTABLE_AMOUNT_SIZE]; - - const pb_bytes_array_16_t *in_amount; - if (ctx->subcommand == SELL) { - in_amount = (pb_bytes_array_16_t *) &ctx->sell_transaction.in_amount; + pb_bytes_array_16_t *in_amount; + if (G_swap_ctx.subcommand == SELL) { + in_amount = (pb_bytes_array_16_t *) &G_swap_ctx.sell_transaction.in_amount; } else { - in_amount = (pb_bytes_array_16_t *) &ctx->fund_transaction.in_amount; + in_amount = (pb_bytes_array_16_t *) &G_swap_ctx.fund_transaction.in_amount; } // getting printable amount - if (get_printable_amount(&ctx->payin_coin_config, - ctx->payin_binary_name, - in_amount->bytes, + if (get_printable_amount(&G_swap_ctx.payin_coin_config, + G_swap_ctx.payin_binary_name, + (uint8_t *) in_amount->bytes, in_amount->size, - in_printable_amount, - sizeof(in_printable_amount), + G_swap_ctx.printable_send_amount, + sizeof(G_swap_ctx.printable_send_amount), false) < 0) { PRINTF("Error: Failed to get CRYPTO currency printable amount\n"); - return reply_error(ctx, INTERNAL_ERROR, send); + return reply_error(INTERNAL_ERROR); } - PRINTF("Amount = %s\n", in_printable_amount); - - static char printable_fees_amount[MAX_PRINTABLE_AMOUNT_SIZE]; - memset(printable_fees_amount, 0, sizeof(printable_fees_amount)); + PRINTF("Amount = %s\n", G_swap_ctx.printable_send_amount); - if (get_printable_amount(&ctx->payin_coin_config, - ctx->payin_binary_name, - ctx->transaction_fee, - ctx->transaction_fee_length, - printable_fees_amount, - sizeof(printable_fees_amount), + if (get_printable_amount(&G_swap_ctx.payin_coin_config, + G_swap_ctx.payin_binary_name, + (uint8_t *) G_swap_ctx.transaction_fee, + G_swap_ctx.transaction_fee_length, + G_swap_ctx.printable_fees_amount, + sizeof(G_swap_ctx.printable_fees_amount), true) < 0) { PRINTF("Error: Failed to get CRYPTO currency fees amount"); - return reply_error(ctx, INTERNAL_ERROR, send); + return reply_error(INTERNAL_ERROR); } if (cmd->subcommand == SELL) { - size_t len = strlen(ctx->sell_transaction.out_currency); - if (len + 1 >= sizeof(ctx->printable_get_amount)) { - return reply_error(ctx, INTERNAL_ERROR, send); + size_t len = strlen(G_swap_ctx.sell_transaction.out_currency); + if (len + 1 >= sizeof(G_swap_ctx.printable_get_amount)) { + return reply_error(INTERNAL_ERROR); } - strncpy(ctx->printable_get_amount, - ctx->sell_transaction.out_currency, - sizeof(ctx->printable_get_amount)); - ctx->printable_get_amount[len] = ' '; - ctx->printable_get_amount[len + 1] = '\x00'; - - if (get_fiat_printable_amount(ctx->sell_transaction.out_amount.coefficient.bytes, - ctx->sell_transaction.out_amount.coefficient.size, - ctx->sell_transaction.out_amount.exponent, - ctx->printable_get_amount + len + 1, - sizeof(ctx->printable_get_amount) - (len + 1)) < 0) { + strncpy(G_swap_ctx.printable_get_amount, + G_swap_ctx.sell_transaction.out_currency, + sizeof(G_swap_ctx.printable_get_amount)); + G_swap_ctx.printable_get_amount[len] = ' '; + G_swap_ctx.printable_get_amount[len + 1] = '\x00'; + + if (get_fiat_printable_amount(G_swap_ctx.sell_transaction.out_amount.coefficient.bytes, + G_swap_ctx.sell_transaction.out_amount.coefficient.size, + G_swap_ctx.sell_transaction.out_amount.exponent, + G_swap_ctx.printable_get_amount + len + 1, + sizeof(G_swap_ctx.printable_get_amount) - (len + 1)) < 0) { PRINTF("Error: Failed to get source currency printable amount\n"); - return reply_error(ctx, INTERNAL_ERROR, send); + return reply_error(INTERNAL_ERROR); } - PRINTF("%s\n", ctx->printable_get_amount); + PRINTF("%s\n", G_swap_ctx.printable_get_amount); } else { // Prepare message for account funding - strncpy(ctx->printable_get_amount, - ctx->fund_transaction.account_name, - sizeof(ctx->printable_get_amount)); - ctx->printable_get_amount[sizeof(ctx->printable_get_amount) - 1] = '\x00'; + strncpy(G_swap_ctx.printable_get_amount, + G_swap_ctx.fund_transaction.account_name, + sizeof(G_swap_ctx.printable_get_amount)); + G_swap_ctx.printable_get_amount[sizeof(G_swap_ctx.printable_get_amount) - 1] = '\x00'; } - ctx->state = WAITING_USER_VALIDATION; + G_swap_ctx.state = WAITING_USER_VALIDATION; - ui_validate_amounts(cmd->rate, // - cmd->subcommand, - ctx, // - in_printable_amount, // - printable_fees_amount, // - send); + ui_validate_amounts(); return 0; } diff --git a/src/check_asset_in.h b/src/check_asset_in.h index a1e6539c..20535277 100644 --- a/src/check_asset_in.h +++ b/src/check_asset_in.h @@ -1,10 +1,5 @@ -#ifndef _CHECK_ASSET_IN_H_ -#define _CHECK_ASSET_IN_H_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int check_asset_in(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif // _CHECK_ASSET_IN_H_ +int check_asset_in(const command_t *cmd); diff --git a/src/check_partner.c b/src/check_partner.c index 47e9f001..2f0aac98 100644 --- a/src/check_partner.c +++ b/src/check_partner.c @@ -4,39 +4,36 @@ #include "check_partner.h" #include "globals.h" #include "swap_errors.h" -#include "reply_error.h" +#include "io.h" // This function receive signature of // Input should be in the form of DER serialized signature // the length should be in [MIN_DER_SIGNATURE_LENGTH, MAX_DER_SIGNATURE_LENGTH] -int check_partner(swap_app_context_t *ctx, const command_t *cmd, SendFunction send) { +int check_partner(const command_t *cmd) { if (cmd->data.size < MIN_DER_SIGNATURE_LENGTH || cmd->data.size > MAX_DER_SIGNATURE_LENGTH) { PRINTF("Error: Input buffer length don't correspond to DER length\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } - if (cx_ecdsa_verify(&(ctx->ledger_public_key), + if (cx_ecdsa_verify(&(G_swap_ctx.ledger_public_key), CX_LAST, CX_SHA256, - ctx->sha256_digest, + G_swap_ctx.sha256_digest, CURVE_SIZE_BYTES, cmd->data.bytes, cmd->data.size) == 0) { PRINTF("Error: Failed to verify signature of partner data\n"); - return reply_error(ctx, SIGN_VERIFICATION_FAIL, send); + return reply_error(SIGN_VERIFICATION_FAIL); } - unsigned char output_buffer[2] = {0x90, 0x00}; - - if (send(output_buffer, 2) < 0) { + if (reply_success() < 0) { PRINTF("Error: send error\n"); - return -1; } - ctx->state = PROVIDER_CHECKED; + G_swap_ctx.state = PROVIDER_CHECKED; return 0; } diff --git a/src/check_partner.h b/src/check_partner.h index f962b97a..27dc59a9 100644 --- a/src/check_partner.h +++ b/src/check_partner.h @@ -1,10 +1,5 @@ -#ifndef _CHECK_PARTNER_H_ -#define _CHECK_PARTNER_H_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int check_partner(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif // _CHECK_PARTNER_H_ +int check_partner(const command_t *cmd); diff --git a/src/check_payout_address.c b/src/check_payout_address.c index ed111d80..49779131 100644 --- a/src/check_payout_address.c +++ b/src/check_payout_address.c @@ -5,13 +5,13 @@ #include "swap_errors.h" #include "globals.h" #include "currency_lib_calls.h" -#include "reply_error.h" +#include "io.h" #include "parse_check_address_message.h" #include "parse_coin_config.h" #include "printable_amount.h" #include "menu.h" -int check_payout_address(swap_app_context_t *ctx, const command_t *cmd, SendFunction send) { +int check_payout_address(const command_t *cmd) { static buf_t config; static buf_t der; static buf_t address_parameters; @@ -21,16 +21,16 @@ int check_payout_address(swap_app_context_t *ctx, const command_t *cmd, SendFunc if (parse_check_address_message(cmd, &config, &der, &address_parameters) == 0) { PRINTF("Error: Can't parse CHECK_PAYOUT_ADDRESS command\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } PRINTF("CHECK_PAYOUT_ADDRESS parsed OK\n"); - static unsigned char hash[CURVE_SIZE_BYTES]; + uint8_t hash[CURVE_SIZE_BYTES]; cx_hash_sha256(config.bytes, config.size, hash, CURVE_SIZE_BYTES); - if (cx_ecdsa_verify(&ctx->ledger_public_key, + if (cx_ecdsa_verify(&G_swap_ctx.ledger_public_key, CX_LAST, CX_SHA256, hash, @@ -38,70 +38,69 @@ int check_payout_address(swap_app_context_t *ctx, const command_t *cmd, SendFunc der.bytes, der.size) == 0) { PRINTF("Error: Fail to verify signature of coin config\n"); - return reply_error(ctx, SIGN_VERIFICATION_FAIL, send); + return reply_error(SIGN_VERIFICATION_FAIL); } if (parse_coin_config(&config, &ticker, &application_name, &config) == 0) { PRINTF("Error: Can't parse payout coin config command\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } // Check that given ticker match current context - if (strlen(ctx->received_transaction.currency_to) != ticker.size || - strncmp(ctx->received_transaction.currency_to, (const char *) ticker.bytes, ticker.size) != - 0) { + if (strlen(G_swap_ctx.received_transaction.currency_to) != ticker.size || + strncmp(G_swap_ctx.received_transaction.currency_to, + (const char *) ticker.bytes, + ticker.size) != 0) { PRINTF("Error: Payout ticker doesn't match configuration ticker\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } PRINTF("Coin config parsed OK\n"); // creating 0-terminated application name - memset(ctx->payin_binary_name, 0, sizeof(ctx->payin_binary_name)); - memcpy(ctx->payin_binary_name, application_name.bytes, application_name.size); + memset(G_swap_ctx.payin_binary_name, 0, sizeof(G_swap_ctx.payin_binary_name)); + memcpy(G_swap_ctx.payin_binary_name, application_name.bytes, application_name.size); PRINTF("PATH inside the SWAP = %.*H\n", address_parameters.size, address_parameters.bytes); - if (ctx->received_transaction - .payout_address[sizeof(ctx->received_transaction.payout_address) - 1] != '\0') { + if (G_swap_ctx.received_transaction + .payout_address[sizeof(G_swap_ctx.received_transaction.payout_address) - 1] != '\0') { PRINTF("Address to check is not NULL terminated\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } // check address if (check_address(&config, &address_parameters, - ctx->payin_binary_name, - ctx->received_transaction.payout_address, - ctx->received_transaction.payout_extra_id) != 1) { + G_swap_ctx.payin_binary_name, + G_swap_ctx.received_transaction.payout_address, + G_swap_ctx.received_transaction.payout_extra_id) != 1) { PRINTF("Error: Payout address validation failed\n"); - return reply_error(ctx, INVALID_ADDRESS, send); + return reply_error(INVALID_ADDRESS); } PRINTF("Payout address is OK\n"); // getting printable amount if (get_printable_amount(&config, - ctx->payin_binary_name, - ctx->received_transaction.amount_to_wallet.bytes, - ctx->received_transaction.amount_to_wallet.size, - ctx->printable_get_amount, - sizeof(ctx->printable_get_amount), + G_swap_ctx.payin_binary_name, + (uint8_t *) G_swap_ctx.received_transaction.amount_to_wallet.bytes, + G_swap_ctx.received_transaction.amount_to_wallet.size, + G_swap_ctx.printable_get_amount, + sizeof(G_swap_ctx.printable_get_amount), false) < 0) { PRINTF("Error: Failed to get destination currency printable amount\n"); - return reply_error(ctx, INTERNAL_ERROR, send); + return reply_error(INTERNAL_ERROR); } - PRINTF("Amount = %s\n", ctx->printable_get_amount); + PRINTF("Amount = %s\n", G_swap_ctx.printable_get_amount); - unsigned char output_buffer[2] = {0x90, 0x00}; - - if (send(output_buffer, 2) < 0) { + if (reply_success() < 0) { PRINTF("Error: failed to send\n"); return -1; } - ctx->state = TO_ADDR_CHECKED; + G_swap_ctx.state = TO_ADDR_CHECKED; return 0; } diff --git a/src/check_payout_address.h b/src/check_payout_address.h index c5e79bda..62969c25 100644 --- a/src/check_payout_address.h +++ b/src/check_payout_address.h @@ -1,10 +1,5 @@ -#ifndef _CHECK_TO_ADDRESS_H_ -#define _CHECK_TO_ADDRESS_H_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int check_payout_address(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif // _CHECK_TO_ADDRESS_H_ +int check_payout_address(const command_t *cmd); diff --git a/src/check_refund_address.c b/src/check_refund_address.c index 2d2a3eaa..ea4109a1 100644 --- a/src/check_refund_address.c +++ b/src/check_refund_address.c @@ -5,12 +5,13 @@ #include "currency_lib_calls.h" #include "globals.h" #include "swap_errors.h" -#include "reply_error.h" +#include "io.h" #include "parse_check_address_message.h" #include "menu.h" +#include "validate_transaction.h" #include "parse_coin_config.h" -int check_refund_address(swap_app_context_t *ctx, const command_t *cmd, SendFunction send) { +int check_refund_address(const command_t *cmd) { static buf_t config; static buf_t der; static buf_t address_parameters; @@ -18,16 +19,16 @@ int check_refund_address(swap_app_context_t *ctx, const command_t *cmd, SendFunc static buf_t application_name; if (parse_check_address_message(cmd, &config, &der, &address_parameters) == 0) { - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } - static unsigned char hash[CURVE_SIZE_BYTES]; + uint8_t hash[CURVE_SIZE_BYTES]; memset(hash, 0, sizeof(hash)); cx_hash_sha256(config.bytes, config.size, hash, CURVE_SIZE_BYTES); - if (cx_ecdsa_verify(&ctx->ledger_public_key, + if (cx_ecdsa_verify(&G_swap_ctx.ledger_public_key, CX_LAST, CX_SHA256, hash, @@ -36,89 +37,79 @@ int check_refund_address(swap_app_context_t *ctx, const command_t *cmd, SendFunc der.size) == 0) { PRINTF("Error: Fail to verify signature of coin config\n"); - return reply_error(ctx, SIGN_VERIFICATION_FAIL, send); + return reply_error(SIGN_VERIFICATION_FAIL); } - if (parse_coin_config(&config, &ticker, &application_name, &ctx->payin_coin_config) == 0) { + if (parse_coin_config(&config, &ticker, &application_name, &G_swap_ctx.payin_coin_config) == + 0) { PRINTF("Error: Can't parse refund coin config command\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } // Check that given ticker match current context - if (strlen(ctx->received_transaction.currency_from) != ticker.size || - strncmp(ctx->received_transaction.currency_from, // - (const char *) ticker.bytes, // + if (strlen(G_swap_ctx.received_transaction.currency_from) != ticker.size || + strncmp(G_swap_ctx.received_transaction.currency_from, // + (const char *) ticker.bytes, // ticker.size) != 0) { PRINTF("Error: Refund ticker doesn't match configuration ticker\n %.*H vs %.*H\n", 10, - ctx->received_transaction.currency_from, + G_swap_ctx.received_transaction.currency_from, ticker.size, ticker.bytes); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } // creating 0-terminated application name - memset(ctx->payin_binary_name, 0, sizeof(ctx->payin_binary_name)); - memcpy(ctx->payin_binary_name, application_name.bytes, application_name.size); + memset(G_swap_ctx.payin_binary_name, 0, sizeof(G_swap_ctx.payin_binary_name)); + memcpy(G_swap_ctx.payin_binary_name, application_name.bytes, application_name.size); - if (ctx->received_transaction - .refund_address[sizeof(ctx->received_transaction.refund_address) - 1] != '\0') { + if (G_swap_ctx.received_transaction + .refund_address[sizeof(G_swap_ctx.received_transaction.refund_address) - 1] != '\0') { PRINTF("Address to check is not NULL terminated\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } // check address - if (check_address(&ctx->payin_coin_config, + if (check_address(&G_swap_ctx.payin_coin_config, &address_parameters, - ctx->payin_binary_name, - ctx->received_transaction.refund_address, - ctx->received_transaction.refund_extra_id) != 1) { + G_swap_ctx.payin_binary_name, + G_swap_ctx.received_transaction.refund_address, + G_swap_ctx.received_transaction.refund_extra_id) != 1) { PRINTF("Error: Refund address validation failed\n"); - return reply_error(ctx, INVALID_ADDRESS, send); + return reply_error(INVALID_ADDRESS); } - static char printable_send_amount[MAX_PRINTABLE_AMOUNT_SIZE]; - memset(printable_send_amount, 0, sizeof(printable_send_amount)); - - if (get_printable_amount(&ctx->payin_coin_config, - ctx->payin_binary_name, - ctx->received_transaction.amount_to_provider.bytes, - ctx->received_transaction.amount_to_provider.size, - printable_send_amount, - sizeof(printable_send_amount), + if (get_printable_amount(&G_swap_ctx.payin_coin_config, + G_swap_ctx.payin_binary_name, + G_swap_ctx.received_transaction.amount_to_provider.bytes, + G_swap_ctx.received_transaction.amount_to_provider.size, + G_swap_ctx.printable_send_amount, + sizeof(G_swap_ctx.printable_send_amount), false) < 0) { PRINTF("Error: Failed to get source currency printable amount\n"); - return reply_error(ctx, INTERNAL_ERROR, send); + return reply_error(INTERNAL_ERROR); } - PRINTF("Send amount: %s\n", printable_send_amount); - - static char printable_fees_amount[MAX_PRINTABLE_AMOUNT_SIZE]; - memset(printable_fees_amount, 0, sizeof(printable_fees_amount)); - - if (get_printable_amount(&ctx->payin_coin_config, - ctx->payin_binary_name, - ctx->transaction_fee, - ctx->transaction_fee_length, - printable_fees_amount, - sizeof(printable_fees_amount), + PRINTF("Send amount: %s\n", G_swap_ctx.printable_send_amount); + + if (get_printable_amount(&G_swap_ctx.payin_coin_config, + G_swap_ctx.payin_binary_name, + G_swap_ctx.transaction_fee, + G_swap_ctx.transaction_fee_length, + G_swap_ctx.printable_fees_amount, + sizeof(G_swap_ctx.printable_fees_amount), true) < 0) { PRINTF("Error: Failed to get source currency fees amount\n"); - return reply_error(ctx, INTERNAL_ERROR, send); + return reply_error(INTERNAL_ERROR); } - PRINTF("Fees: %s\n", printable_fees_amount); + PRINTF("Fees: %s\n", G_swap_ctx.printable_fees_amount); - ctx->state = WAITING_USER_VALIDATION; + G_swap_ctx.state = WAITING_USER_VALIDATION; - ui_validate_amounts(cmd->rate, // - cmd->subcommand, - ctx, // - printable_send_amount, // - printable_fees_amount, // - send); + ui_validate_amounts(); return 0; } diff --git a/src/check_refund_address.h b/src/check_refund_address.h index c351443e..5d241eaf 100644 --- a/src/check_refund_address.h +++ b/src/check_refund_address.h @@ -1,10 +1,5 @@ -#ifndef _CHECK_REFUND_ADDRESS_H_ -#define _CHECK_REFUND_ADDRESS_H_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int check_refund_address(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif // _CHECK_REFUND_ADDRESS_H_ +int check_refund_address(const command_t *cmd); diff --git a/src/check_tx_signature.c b/src/check_tx_signature.c index 5d40eb62..4e05d9e4 100644 --- a/src/check_tx_signature.c +++ b/src/check_tx_signature.c @@ -4,7 +4,7 @@ #include "check_tx_signature.h" #include "globals.h" #include "swap_errors.h" -#include "reply_error.h" +#include "io.h" #include "der.h" #define MAX_DER_INT_SIZE(size) (1 + 3 + (size) + 1) @@ -12,29 +12,29 @@ // This function receive transaction signature // Input should be in the form of DER serialized signature // the length should be CURVE_SIZE_BYTES * 2 + 6 (DER encoding) -int check_tx_signature(swap_app_context_t *ctx, const command_t *cmd, SendFunction send) { +int check_tx_signature(const command_t *cmd) { if (cmd->subcommand == SWAP || cmd->subcommand == FUND) { if (cmd->data.size < MIN_DER_SIGNATURE_LENGTH || cmd->data.size > MAX_DER_SIGNATURE_LENGTH || cmd->data.bytes[1] + 2 != cmd->data.size) { PRINTF("Error: Input buffer length don't correspond to DER length\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } - if (cx_ecdsa_verify(&ctx->partner.public_key, + if (cx_ecdsa_verify(&G_swap_ctx.partner.public_key, CX_LAST, CX_SHA256, - ctx->sha256_digest, + G_swap_ctx.sha256_digest, CURVE_SIZE_BYTES, cmd->data.bytes, cmd->data.size) == 0) { PRINTF("Error: Failed to verify signature of received transaction\n"); - return reply_error(ctx, SIGN_VERIFICATION_FAIL, send); + return reply_error(SIGN_VERIFICATION_FAIL); } } if (cmd->subcommand == SELL) { if (cmd->data.size != 64) { PRINTF("Error: Input buffer length don't correspond to (R, S) length\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } size_t der_r_len = asn1_get_encoded_integer_size(cmd->data.bytes, 32); @@ -44,34 +44,34 @@ int check_tx_signature(swap_app_context_t *ctx, const command_t *cmd, SendFuncti unsigned char der_sig[MAX_DER_INT_SIZE(32) * 2 + 2]; if (size > sizeof(der_sig)) { PRINTF("Error: Unexpected der integer size\n"); - return reply_error(ctx, SIGN_VERIFICATION_FAIL, send); + return reply_error(SIGN_VERIFICATION_FAIL); } encode_sig_der(der_sig, size, cmd->data.bytes, 32, cmd->data.bytes + 32, 32); PRINTF("DER sig: %.*H\n", size, der_sig); - PRINTF("SHA256(payload): %.*H\n", sizeof(ctx->sha256_digest), ctx->sha256_digest); + PRINTF("SHA256(payload): %.*H\n", + sizeof(G_swap_ctx.sha256_digest), + G_swap_ctx.sha256_digest); - if (cx_ecdsa_verify(&ctx->partner.public_key, + if (cx_ecdsa_verify(&G_swap_ctx.partner.public_key, CX_LAST, CX_SHA256, - ctx->sha256_digest, + G_swap_ctx.sha256_digest, CURVE_SIZE_BYTES, der_sig, size) == 0) { PRINTF("Error: Failed to verify signature of received transaction\n"); - return reply_error(ctx, SIGN_VERIFICATION_FAIL, send); + return reply_error(SIGN_VERIFICATION_FAIL); } } - unsigned char output_buffer[2] = {0x90, 0x00}; - - if (send(output_buffer, 2) < 0) { + if (reply_success() < 0) { PRINTF("Error: Can't send message\n"); return -1; } - ctx->state = SIGNATURE_CHECKED; + G_swap_ctx.state = SIGNATURE_CHECKED; return 0; } diff --git a/src/check_tx_signature.h b/src/check_tx_signature.h index 65d53fdf..ff7f0fcd 100644 --- a/src/check_tx_signature.h +++ b/src/check_tx_signature.h @@ -1,10 +1,5 @@ -#ifndef _CHECK_TX_SIGNATURE_H_ -#define _CHECK_TX_SIGNATURE_H_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int check_tx_signature(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif // _CHECK_TX_SIGNATURE_H_ +int check_tx_signature(const command_t *cmd); diff --git a/src/command_dispatcher.c b/src/command_dispatcher.c index 877b0345..aa6cbfe2 100644 --- a/src/command_dispatcher.c +++ b/src/command_dispatcher.c @@ -1,9 +1,8 @@ #include "command_dispatcher.h" #include "os.h" -#include "swap_app_context.h" +#include "globals.h" #include "get_version_handler.h" -#include "unexpected_command.h" #include "start_new_transaction.h" #include "set_partner_key.h" #include "process_transaction.h" @@ -15,79 +14,95 @@ #include "check_partner.h" #include "start_signing_transaction.h" -#include "reply_error.h" +#include "io.h" -typedef int (*StateCommandDispatcher)(swap_app_context_t *ctx, - const command_t *cmd, - SendFunction send); - -int dispatch_command(swap_app_context_t *context, const command_t *cmd, SendFunction send) { - StateCommandDispatcher handler; - - PRINTF("command: %d, subcommand: %d, state: %d\n", cmd->ins, cmd->subcommand, context->state); +int dispatch_command(const command_t *cmd) { + PRINTF("command: %d, subcommand: %d, state: %d\n", cmd->ins, cmd->subcommand, G_swap_ctx.state); if (cmd->rate != FIXED && cmd->rate != FLOATING) { - return reply_error(context, WRONG_P1, send); + return reply_error(WRONG_P1); } if (cmd->subcommand != SWAP && cmd->subcommand != SELL && cmd->subcommand != FUND) { - return reply_error(context, WRONG_P2, send); + return reply_error(WRONG_P2); } - handler = (void *) PIC(unexpected_command); + int ret = -1; + bool valid_command_received = false; switch (cmd->ins) { case GET_VERSION_COMMAND: - if (context->state != WAITING_USER_VALIDATION && context->state != WAITING_SIGNING) { - handler = (void *) PIC(get_version_handler); + if (G_swap_ctx.state != WAITING_USER_VALIDATION && + G_swap_ctx.state != WAITING_SIGNING) { + ret = get_version_handler(); + valid_command_received = true; } break; case START_NEW_TRANSACTION_COMMAND: - if (context->state != WAITING_USER_VALIDATION) { - handler = (void *) PIC(start_new_transaction); + if (G_swap_ctx.state != WAITING_USER_VALIDATION) { + ret = start_new_transaction(cmd); + valid_command_received = true; } break; case SET_PARTNER_KEY_COMMAND: - if (context->state == WAITING_TRANSACTION && cmd->subcommand == context->subcommand) { - handler = (void *) PIC(set_partner_key); + if (G_swap_ctx.state == WAITING_TRANSACTION && + cmd->subcommand == G_swap_ctx.subcommand && cmd->rate == G_swap_ctx.rate) { + ret = set_partner_key(cmd); + valid_command_received = true; } break; case CHECK_PARTNER_COMMAND: - if (context->state == PROVIDER_SET && cmd->subcommand == context->subcommand) { - handler = (void *) PIC(check_partner); + if (G_swap_ctx.state == PROVIDER_SET && cmd->subcommand == G_swap_ctx.subcommand && + cmd->rate == G_swap_ctx.rate) { + ret = check_partner(cmd); + valid_command_received = true; } break; case PROCESS_TRANSACTION_RESPONSE_COMMAND: - if (context->state == PROVIDER_CHECKED && cmd->subcommand == context->subcommand) { - handler = (void *) PIC(process_transaction); + if (G_swap_ctx.state == PROVIDER_CHECKED && cmd->subcommand == G_swap_ctx.subcommand && + cmd->rate == G_swap_ctx.rate) { + ret = process_transaction(cmd); + valid_command_received = true; } break; case CHECK_TRANSACTION_SIGNATURE_COMMAND: - if (context->state == TRANSACTION_RECEIVED && cmd->subcommand == context->subcommand) { - handler = (void *) PIC(check_tx_signature); + if (G_swap_ctx.state == TRANSACTION_RECEIVED && + cmd->subcommand == G_swap_ctx.subcommand && cmd->rate == G_swap_ctx.rate) { + ret = check_tx_signature(cmd); + valid_command_received = true; } break; case CHECK_PAYOUT_ADDRESS: - if (context->state == SIGNATURE_CHECKED && cmd->subcommand == context->subcommand) { + if (G_swap_ctx.state == SIGNATURE_CHECKED && cmd->subcommand == G_swap_ctx.subcommand && + cmd->rate == G_swap_ctx.rate) { if (cmd->subcommand == SELL || cmd->subcommand == FUND) { - handler = (void *) PIC(check_asset_in); + ret = check_asset_in(cmd); } else { - handler = (void *) PIC(check_payout_address); + ret = check_payout_address(cmd); } + valid_command_received = true; } break; case CHECK_REFUND_ADDRESS: - if (context->state == TO_ADDR_CHECKED && cmd->subcommand == context->subcommand) { - handler = (void *) PIC(check_refund_address); + if (G_swap_ctx.state == TO_ADDR_CHECKED && cmd->subcommand == G_swap_ctx.subcommand && + cmd->rate == G_swap_ctx.rate) { + ret = check_refund_address(cmd); + valid_command_received = true; } break; case START_SIGNING_TRANSACTION: - if (context->state == WAITING_SIGNING && cmd->subcommand == context->subcommand) { - handler = (void *) PIC(start_signing_transaction); + if (G_swap_ctx.state == WAITING_SIGNING && cmd->subcommand == G_swap_ctx.subcommand && + cmd->rate == G_swap_ctx.rate) { + ret = start_signing_transaction(cmd); + valid_command_received = true; } break; default: break; } - return handler(context, cmd, send); + if (!valid_command_received) { + ret = reply_error(INVALID_INSTRUCTION); + } + + return ret; } diff --git a/src/command_dispatcher.h b/src/command_dispatcher.h index f3bccfef..1c0681e4 100644 --- a/src/command_dispatcher.h +++ b/src/command_dispatcher.h @@ -1,10 +1,5 @@ -#ifndef _COMMAND_DISPATCHER_H_ -#define _COMMAND_DISPATCHER_H_ +#pragma once -#include "send_function.h" #include "commands.h" -#include "swap_app_context.h" -int dispatch_command(swap_app_context_t *context, const command_t *cmd, SendFunction send); - -#endif //_COMMAND_DISPATCHER_H_ +int dispatch_command(const command_t *cmd); diff --git a/src/currency_lib_calls.c b/src/currency_lib_calls.c index 493b256e..b81d54eb 100644 --- a/src/currency_lib_calls.c +++ b/src/currency_lib_calls.c @@ -1,7 +1,6 @@ #include #include "os_io_seproxyhal.h" -#include "ux.h" #include "os.h" #include "currency_lib_calls.h" @@ -35,13 +34,13 @@ `libcall_params[4]` -> `libargs_s` union */ -int get_printable_amount(const buf_t *const coin_config, - const char *const application_name, - const unsigned char *const amount, - const unsigned char amount_size, - char *const printable_amount, - const unsigned char printable_amount_size, - const bool is_fee) { +int get_printable_amount(buf_t *coin_config, + char *application_name, + unsigned char *amount, + unsigned char amount_size, + char *printable_amount, + unsigned char printable_amount_size, + bool is_fee) { static unsigned int libcall_params[5]; static get_printable_amount_parameters_t lib_input_params = {0}; lib_input_params.coin_configuration = coin_config->bytes; diff --git a/src/currency_lib_calls.h b/src/currency_lib_calls.h index 43e40ad7..b1b5b176 100644 --- a/src/currency_lib_calls.h +++ b/src/currency_lib_calls.h @@ -14,12 +14,12 @@ int check_address(buf_t *coin_config, void create_payin_transaction(char *application_name, create_transaction_parameters_t *params); -int get_printable_amount(const buf_t *const coin_config, - const char *const application_name, - const unsigned char *const amount, - const unsigned char amount_size, - char *const printable_amount, - const unsigned char printable_amount_size, - const bool is_fee); +int get_printable_amount(buf_t *coin_config, + char *application_name, + unsigned char *amount, + unsigned char amount_size, + char *printable_amount, + unsigned char printable_amount_size, + bool is_fee); #endif // _SOURCE_CURRENCY_LIB_CALLS_H_ diff --git a/src/get_version_handler.c b/src/get_version_handler.c index f3761407..8d46ba3f 100644 --- a/src/get_version_handler.c +++ b/src/get_version_handler.c @@ -1,15 +1,14 @@ #include "get_version_handler.h" +#include "io.h" -int get_version_handler(__attribute__((unused)) swap_app_context_t *ctx, - __attribute__((unused)) const command_t *cmd, - SendFunction send) { +int get_version_handler(void) { unsigned char output_buffer[5]; output_buffer[0] = LEDGER_MAJOR_VERSION; output_buffer[1] = LEDGER_MINOR_VERSION; output_buffer[2] = LEDGER_PATCH_VERSION; output_buffer[3] = 0x90; output_buffer[4] = 0x00; - if (send(output_buffer, 5) < 0) { + if (send_apdu(output_buffer, 5) < 0) { return -1; } return 0; diff --git a/src/get_version_handler.h b/src/get_version_handler.h index 25d1020e..79dbb04d 100644 --- a/src/get_version_handler.h +++ b/src/get_version_handler.h @@ -1,10 +1,5 @@ -#ifndef _GET_VERSION_HANDLER_ -#define _GET_VERSION_HANDLER_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int get_version_handler(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif +int get_version_handler(); diff --git a/src/globals.h b/src/globals.h index 867b4061..cebbbd45 100644 --- a/src/globals.h +++ b/src/globals.h @@ -2,6 +2,11 @@ #include "os.h" #include "os_io_seproxyhal.h" +#include "states.h" +#include "commands.h" +#include "protocol.pb.h" +#include "buffer.h" +#include "swap_lib_calls.h" #define P1_CONFIRM 0x01 #define P1_NON_CONFIRM 0x00 @@ -16,3 +21,70 @@ #define TICKER_MIN_SIZE_B 2 #define TICKER_MAX_SIZE_B 9 #define APPNAME_MIN_SIZE_B 3 + +extern uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; + +#define MIN_PARTNER_NAME_LENGHT 3 +#define MAX_PARTNER_NAME_LENGHT 15 + +#define PARTNER_NAME_PREFIX_FOR_FUND "To " +#define PARTNER_NAME_PREFIX_SIZE (sizeof(PARTNER_NAME_PREFIX_FOR_FUND) - 1) // Remove trailing '\0' + +#pragma pack(push, 1) +typedef struct partner_data_s { + unsigned char name_length; + union { + // SELL and SWAP flows display nothing + // FUND flow displays "To xyz" + struct { + char prefix[PARTNER_NAME_PREFIX_SIZE]; + char name[MAX_PARTNER_NAME_LENGHT + 1]; + }; + char prefixed_name[PARTNER_NAME_PREFIX_SIZE + MAX_PARTNER_NAME_LENGHT + 1]; + }; + cx_ecfp_256_public_key_t public_key; +} partner_data_t; +#pragma pack(pop) + +typedef struct swap_app_context_s { + union { + unsigned char sell_fund[32]; // device_transaction_id (SELL && FUND) + char swap[10]; // device_transaction_id (SWAP) + } device_transaction_id; + + unsigned char transaction_fee[16]; + unsigned char transaction_fee_length; + + partner_data_t partner; + state_e state; + subcommand_e subcommand; + rate_e rate; + + // SWAP, SELL, and FUND flows are unionized as they cannot be used in the same context + union { + ledger_swap_NewTransactionResponse received_transaction; + struct { + ledger_swap_NewSellResponse sell_transaction; + // Field not received from protobuf but needed by the application called as lib + char sell_transaction_extra_id[1]; + }; + struct { + ledger_swap_NewFundResponse fund_transaction; + // Field not received from protobuf but needed by the application called as lib + char fund_transaction_extra_id[1]; + }; + }; + + unsigned char sha256_digest[32]; + + cx_ecfp_256_public_key_t ledger_public_key; + + buf_t payin_coin_config; // serialized coin configuration + char payin_binary_name[16]; + + char printable_get_amount[MAX_PRINTABLE_AMOUNT_SIZE]; + char printable_send_amount[MAX_PRINTABLE_AMOUNT_SIZE]; + char printable_fees_amount[MAX_PRINTABLE_AMOUNT_SIZE]; +} swap_app_context_t; + +extern swap_app_context_t G_swap_ctx; diff --git a/src/init.c b/src/init.c index cab43276..73adc1a7 100644 --- a/src/init.c +++ b/src/init.c @@ -1,8 +1,9 @@ +#include "globals.h" #include "init.h" #include "cx.h" // Init public keys -void init_application_context(swap_app_context_t *ctx) { +void init_application_context(void) { #if defined(TEST_PUBLIC_KEY) // this key is the ERC20signer test key unsigned char LedgerPubKey[] = {0x4, // @@ -41,10 +42,13 @@ void init_application_context(swap_app_context_t *ctx) { 0x06, 0x0c, 0x53, 0x86, 0x2c, 0x5c, 0xe3, 0x8c}; #endif - memset(ctx, 0, sizeof(*ctx)); + memset(&G_swap_ctx, 0, sizeof(G_swap_ctx)); + memcpy(&G_swap_ctx.partner.prefix, + PARTNER_NAME_PREFIX_FOR_FUND, + sizeof(G_swap_ctx.partner.prefix)); cx_ecfp_init_public_key(CX_CURVE_SECP256K1, LedgerPubKey, sizeof(LedgerPubKey), - &(ctx->ledger_public_key)); - ctx->state = INITIAL_STATE; + &(G_swap_ctx.ledger_public_key)); + G_swap_ctx.state = INITIAL_STATE; } diff --git a/src/init.h b/src/init.h index 2e3aa774..df26aa44 100644 --- a/src/init.h +++ b/src/init.h @@ -1,8 +1,5 @@ -#ifndef _INIT_H_ -#define _INIT_H_ +#pragma once -#include "swap_app_context.h" +#include "globals.h" -void init_application_context(swap_app_context_t *ctx); - -#endif //_INIT_H_ \ No newline at end of file +void init_application_context(void); diff --git a/src/io.c b/src/io.c new file mode 100644 index 00000000..6f7b9f47 --- /dev/null +++ b/src/io.c @@ -0,0 +1,180 @@ +/***************************************************************************** + * Ledger App Boilerplate. + * (c) 2021 Ledger SAS. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *****************************************************************************/ + +#include +#include + +#include "os.h" +#include "ux.h" +#include "globals.h" +#include "swap_errors.h" + +#ifdef HAVE_NBGL +#include "nbgl_touch.h" +#include "nbgl_page.h" +#endif // HAVE_NBGL + +#ifdef HAVE_BAGL +void io_seproxyhal_display(const bagl_element_t *element) { + io_seproxyhal_display_default(element); +} +#endif // HAVE_BAGL + +uint8_t io_event(uint8_t channel) { + (void) channel; + + switch (G_io_seproxyhal_spi_buffer[0]) { + case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: +#ifdef HAVE_BAGL + UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); +#endif // HAVE_BAGL + break; + case SEPROXYHAL_TAG_STATUS_EVENT: + if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && // + !(U4BE(G_io_seproxyhal_spi_buffer, 3) & // + SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { + THROW(EXCEPTION_IO_RESET); + } + /* fallthrough */ + __attribute__((fallthrough)); + case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: +#ifdef HAVE_BAGL + UX_DISPLAYED_EVENT({}); +#endif // HAVE_BAGL +#ifdef HAVE_NBGL + UX_DEFAULT_EVENT(); +#endif // HAVE_NBGL + break; +#ifdef HAVE_NBGL + case SEPROXYHAL_TAG_FINGER_EVENT: + UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); + break; +#endif // HAVE_NBGL + case SEPROXYHAL_TAG_TICKER_EVENT: + UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); + break; + default: + UX_DEFAULT_EVENT(); + break; + } + + if (!io_seproxyhal_spi_is_status_sent()) { + io_seproxyhal_general_status(); + } + + return 1; +} + +uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len) { + switch (channel & ~(IO_FLAGS)) { + case CHANNEL_KEYBOARD: + break; + case CHANNEL_SPI: + if (tx_len) { + io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); + + if (channel & IO_RESET_AFTER_REPLIED) { + halt(); + } + + return 0; + } else { + return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); + } + default: + THROW(INVALID_PARAMETER); + } + + return 0; +} + +// recv() +// send() +// recv() +// UI +// recv(ASYNC) +// send()->io_exchange(RETURN) +// recv() +// +// READY RECEIVED WAITING_USER +// recv() to Received ASYNC+to waiting ERROR +// send() ERROR to ready RETURN_AFTER_RX + to ready + +typedef enum io_state { READY, RECEIVED, WAITING_USER } io_state_e; + +int output_length = 0; +io_state_e io_state = READY; + +void init_io(void) { + output_length = 0; + io_state = READY; +} + +int recv_apdu(void) { + PRINTF("Im inside recv_apdu\n"); + switch (io_state) { + case READY: + PRINTF("In state READY\n"); + io_state = RECEIVED; + return io_exchange(CHANNEL_APDU, output_length); + case RECEIVED: + PRINTF("In state RECEIVED\n"); + io_state = WAITING_USER; + int ret = io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, output_length); + io_state = RECEIVED; + return ret; + case WAITING_USER: + PRINTF("Error: Unexpected recv call in WAITING_USER state\n"); + io_state = READY; + return -1; + }; + PRINTF("ERROR unknown state\n"); + return -1; +} + +// return -1 in case of error +int send_apdu(uint8_t *buffer, size_t buffer_length) { + memmove(G_io_apdu_buffer, buffer, buffer_length); + output_length = buffer_length; + PRINTF("Sending apdu\n"); + switch (io_state) { + case READY: + PRINTF("Error: Unexpected send call in READY state\n"); + return -1; + case RECEIVED: + io_state = READY; + return 0; + case WAITING_USER: + PRINTF("Sending reply with IO_RETURN_AFTER_TX\n"); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, output_length); + output_length = 0; + io_state = READY; + return 0; + } + PRINTF("Error: Unknown io_state\n"); + return -1; +} + +int reply_error(swap_error_e error) { + uint8_t output_buffer[2] = {(error >> 8) & 0xFF, error & 0xFF}; + return send_apdu(output_buffer, 2); +} + +int reply_success(void) { + uint8_t output_buffer[2] = {0x90, 0x00}; + return send_apdu(output_buffer, 2); +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 00000000..161168eb --- /dev/null +++ b/src/io.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "ux.h" +#include "os_io_seproxyhal.h" +#include "swap_errors.h" + +#ifdef HAVE_BAGL +void io_seproxyhal_display(const bagl_element_t *element); +#endif // HAVE_BAGL + +/** + * IO callback called when an interrupt based channel has received + * data to be processed. + * + * @return 1 if success, 0 otherwise. + * + */ +uint8_t io_event(uint8_t channel); + +uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len); + +void init_io(void); + +int recv_apdu(void); + +int send_apdu(uint8_t *buffer, size_t buffer_length); + +int reply_error(swap_error_e error); + +int reply_success(void); diff --git a/src/main.c b/src/main.c index 326e293f..ef47066a 100644 --- a/src/main.c +++ b/src/main.c @@ -16,89 +16,31 @@ *****************************************************************************/ #include "os.h" +#include "ux.h" #include "os_io_seproxyhal.h" #include "init.h" +#include "io.h" #include "menu.h" -#include "swap_app_context.h" +#include "globals.h" #include "commands.h" #include "command_dispatcher.h" #include "apdu_offsets.h" #include "swap_errors.h" -#include "reply_error.h" #include "usbd_core.h" #define CLA 0xE0 -unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -swap_app_context_t swap_ctx; - -// recv() -// send() -// recv() -// UI -// recv(ASYNC) -// send()->io_exchange(RETURN) -// recv() -// -// READY RECEIVED WAITING_USER -// recv() to Received ASYNC+to waiting ERROR -// send() ERROR to ready RETURN_AFTER_RX + to ready - -typedef enum io_state { READY, RECEIVED, WAITING_USER } io_state_e; - -int output_length = 0; -io_state_e io_state = READY; - -int recv_apdu() { - PRINTF("Im inside recv_apdu\n"); - switch (io_state) { - case READY: - PRINTF("In state READY\n"); - io_state = RECEIVED; - return io_exchange(CHANNEL_APDU, output_length); - case RECEIVED: - PRINTF("In state RECEIVED\n"); - io_state = WAITING_USER; - int ret = io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, output_length); - io_state = RECEIVED; - return ret; - case WAITING_USER: - PRINTF("Error: Unexpected recv call in WAITING_USER state\n"); - io_state = READY; - return -1; - }; - PRINTF("ERROR unknown state\n"); - return -1; -} +ux_state_t G_ux; +bolos_ux_params_t G_ux_params; -// return -1 in case of error -int send_apdu(unsigned char *buffer, unsigned int buffer_length) { - memmove(G_io_apdu_buffer, buffer, buffer_length); - output_length = buffer_length; - PRINTF("Sending apdu\n"); - switch (io_state) { - case READY: - PRINTF("Error: Unexpected send call in READY state\n"); - return -1; - case RECEIVED: - io_state = READY; - return 0; - case WAITING_USER: - PRINTF("Sending reply with IO_RETURN_AFTER_TX\n"); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, output_length); - output_length = 0; - io_state = READY; - return 0; - } - PRINTF("Error: Unknown io_state\n"); - return -1; -} +unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; +swap_app_context_t G_swap_ctx; void app_main(void) { int input_length = 0; - output_length = 0; - io_state = READY; + init_io(); + for (;;) { input_length = recv_apdu(); PRINTF("New APDU received:\n%.*H\n", input_length, G_io_apdu_buffer); @@ -106,7 +48,7 @@ void app_main(void) { return; if (input_length < OFFSET_CDATA || G_io_apdu_buffer[OFFSET_CLA] != CLA) { PRINTF("Error: bad APDU\n"); - reply_error(&swap_ctx, INVALID_INSTRUCTION, send_apdu); + reply_error(INVALID_INSTRUCTION); continue; } @@ -121,12 +63,9 @@ void app_main(void) { }, }; - if (dispatch_command(&swap_ctx, // - &cmd, // - send_apdu) < 0) - return; // some non recoverable error happened + if (dispatch_command(&cmd) < 0) return; // some non recoverable error happened - if (swap_ctx.state == INITIAL_STATE) { + if (G_swap_ctx.state == INITIAL_STATE) { ui_idle(); } } @@ -151,7 +90,7 @@ __attribute__((section(".boot"))) int main(__attribute__((unused)) int arg0) { os_boot(); for (;;) { - ux_init(); + UX_INIT(); BEGIN_TRY { TRY { @@ -162,8 +101,6 @@ __attribute__((section(".boot"))) int main(__attribute__((unused)) int arg0) { G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); #endif // TARGET_NANOX - init_application_context(&swap_ctx); - USB_power(0); USB_power(1); diff --git a/src/menu.c b/src/menu.c deleted file mode 100644 index 315f9121..00000000 --- a/src/menu.c +++ /dev/null @@ -1,289 +0,0 @@ -#include "menu.h" -#include "ux.h" -#include "os.h" -#include "globals.h" -#include "glyphs.h" -#include "swap_app_context.h" -#include "send_function.h" -#include "reply_error.h" -#include "commands.h" - -ux_state_t G_ux; -bolos_ux_params_t G_ux_params; - -swap_app_context_t *application_context; -SendFunction send_function; - -void on_accept() { - unsigned char output_buffer[2] = {0x90, 0x00}; - - if (send_function(output_buffer, 2) < 0) { - PRINTF("Error: Failed to send\n"); - return; - } - - application_context->state = WAITING_SIGNING; -} - -void on_reject() { - PRINTF("User refused transaction\n"); - - reply_error(application_context, USER_REFUSED, send_function); -} - -// clang-format off -UX_STEP_NOCB(ux_idle_flow_1_step, nn, -{ - "Exchange", - "is ready", -}); -UX_STEP_NOCB(ux_idle_flow_2_step, bn, -{ - "Version", - APPVERSION, -}); -UX_STEP_VALID(ux_idle_flow_3_step, pb, os_sched_exit(-1), -{ - &C_icon_dashboard_x, - "Quit", -}); - -UX_FLOW(ux_idle_flow, -&ux_idle_flow_1_step, -&ux_idle_flow_2_step, -&ux_idle_flow_3_step, -FLOW_LOOP); -// clang-format on - -////////////////////////// - -#define member_size(type, member) sizeof(((type *) 0)->member) - -struct ValidationInfo { - char email[member_size(swap_app_context_t, sell_transaction.trader_email)]; - char send[MAX_PRINTABLE_AMOUNT_SIZE]; - char get[member_size(swap_app_context_t, printable_get_amount)]; - char fees[MAX_PRINTABLE_AMOUNT_SIZE]; - char provider[MAX_PRINTABLE_AMOUNT_SIZE]; - UserChoiseCallback OnAccept; - UserChoiseCallback OnReject; -} validationInfo; - -unsigned int io_accept(__attribute__((unused)) const bagl_element_t *e) { - validationInfo.OnAccept(); - ui_idle(); - return 0; -} - -unsigned int io_reject(__attribute__((unused)) const bagl_element_t *e) { - validationInfo.OnReject(); - ui_idle(); - return 0; -} - -// clang-format off -UX_STEP_NOCB(ux_confirm_flow_1_step, pnn, -{ - &C_icon_eye, - "Review", - "transaction", -}); -UX_STEP_NOCB(ux_confirm_flow_1_2_step, bnnn_paging, -{ - .title = "Email", - .text = validationInfo.email, -}); -UX_STEP_NOCB(ux_confirm_flow_1_3_step, bnnn_paging, -{ - .title = "User", - .text = validationInfo.email, -}); -UX_STEP_NOCB(ux_confirm_flow_2_step, bnnn_paging, -{ - .title = "Send", - .text = validationInfo.send, -}); -UX_STEP_NOCB(ux_confirm_flow_3_step, bnnn_paging, -{ - .title = "Get", - .text = validationInfo.get, -}); -UX_STEP_NOCB(ux_confirm_flow_3_floating_step, bnnn_paging, -{ - .title = "Get estimated", - .text = validationInfo.get, -}); -UX_STEP_NOCB(ux_confirm_flow_3_2_step, bnnn_paging, -{ - .title = validationInfo.provider, - .text = validationInfo.get, -}); -UX_STEP_NOCB(ux_confirm_flow_4_step, bnnn_paging, -{ - .title = "Fees", - .text = validationInfo.fees, -}); -UX_STEP_CB(ux_confirm_flow_5_step, pbb, io_accept(NULL), -{ - &C_icon_validate_14, - "Accept", - "and send", -}); -UX_STEP_CB(ux_confirm_flow_6_step, pb, io_reject(NULL), -{ - &C_icon_crossmark, - "Reject", -}); - -// clang-format on -const ux_flow_step_t *ux_confirm_flow[8]; - -void ux_confirm(rate_e rate, subcommand_e subcommand) { - int step = 0; - ux_confirm_flow[step++] = &ux_confirm_flow_1_step; - if (subcommand == SELL) { - ux_confirm_flow[step++] = &ux_confirm_flow_1_2_step; - } else if (subcommand == FUND) { - ux_confirm_flow[step++] = &ux_confirm_flow_1_3_step; - } - ux_confirm_flow[step++] = &ux_confirm_flow_2_step; - if (subcommand == FUND) { - ux_confirm_flow[step++] = &ux_confirm_flow_3_2_step; - } else if (rate == FLOATING) { - ux_confirm_flow[step++] = &ux_confirm_flow_3_floating_step; - } else { - ux_confirm_flow[step++] = &ux_confirm_flow_3_step; - } - ux_confirm_flow[step++] = &ux_confirm_flow_4_step; - ux_confirm_flow[step++] = &ux_confirm_flow_5_step; - ux_confirm_flow[step++] = &ux_confirm_flow_6_step; - ux_confirm_flow[step++] = FLOW_END_STEP; - - ux_flow_init(0, ux_confirm_flow, NULL); -} - -void ui_validate_amounts(rate_e rate, - subcommand_e subcommand, - swap_app_context_t *ctx, - char *send_amount, - char *fees_amount, - SendFunction send) { - application_context = ctx; - send_function = send; - - strncpy(validationInfo.send, send_amount, sizeof(validationInfo.send)); - validationInfo.send[sizeof(validationInfo.send) - 1] = '\x00'; - - strncpy(validationInfo.get, ctx->printable_get_amount, sizeof(validationInfo.get)); - validationInfo.get[sizeof(validationInfo.get) - 1] = '\x00'; - - strncpy(validationInfo.fees, fees_amount, sizeof(validationInfo.fees)); - validationInfo.fees[sizeof(validationInfo.fees) - 1] = '\x00'; - - validationInfo.OnAccept = on_accept; - validationInfo.OnReject = on_reject; - - if (subcommand == SELL) { - strncpy(validationInfo.email, - ctx->sell_transaction.trader_email, - sizeof(validationInfo.email)); - validationInfo.email[sizeof(validationInfo.email) - 1] = '\x00'; - } - - if (subcommand == FUND) { - strncpy(validationInfo.email, ctx->fund_transaction.user_id, sizeof(validationInfo.email)); - validationInfo.email[sizeof(validationInfo.email) - 1] = '\x00'; - - strncpy(validationInfo.provider, "To ", 3); - - strncpy(validationInfo.provider + 3, - ctx->partner.name, - sizeof(validationInfo.provider) - 4); - validationInfo.provider[sizeof(validationInfo.provider) - 1] = '\x00'; - } - ux_confirm(rate, subcommand); -} - -void ux_init() { - UX_INIT(); -} - -void ui_idle(void) { - // reserve a display stack slot if none yet - if (G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_idle_flow, NULL); -} - -// override point, but nothing more to do -void io_seproxyhal_display(const bagl_element_t *element) { - io_seproxyhal_display_default((bagl_element_t *) element); -} - -unsigned char io_event(__attribute__((unused)) unsigned char channel) { - // nothing done with the event, throw an error on the transport layer if - // needed - // can't have more than one tag in the reply, not supported yet. - switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: { - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; - } - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - // no break is intentional - default: - UX_DEFAULT_EVENT(); - break; - - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; - - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); - break; - } - - // close the event if not done previously (by a display or whatever) - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - - // command has been processed, DO NOT reset the current APDU transport - return 1; -} - -unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); - } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); - } - - default: - THROW(INVALID_PARAMETER); - } - return 0; -} diff --git a/src/menu.h b/src/menu.h deleted file mode 100644 index 961ce013..00000000 --- a/src/menu.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _MENU_H_ -#define _MENU_H_ - -#include "swap_app_context.h" -#include "send_function.h" -#include "reply_error.h" -#include "commands.h" - -void ux_init(); - -void ui_idle(void); - -typedef void (*UserChoiseCallback)(); - -void ui_validate_amounts(rate_e P1, // - subcommand_e P2, - swap_app_context_t *ctx, // - char *send_amount, // - char *fees_amount, // - SendFunction send); - -#endif diff --git a/src/parse_coin_config.c b/src/parse_coin_config.c index 6eca52e1..d933789d 100644 --- a/src/parse_coin_config.c +++ b/src/parse_coin_config.c @@ -68,7 +68,7 @@ int parse_coin_config(const buf_t *const orig_buffer, if (!strncmp((const char *) application_name->bytes, (char *) (PIC(appnames_aliases[i].foreign_name)), application_name->size)) { - application_name->bytes = (unsigned char *) appnames_aliases[i].app_name; + application_name->bytes = (uint8_t *) appnames_aliases[i].app_name; application_name->size = strlen((char *) PIC(appnames_aliases[i].app_name)); break; } diff --git a/src/process_transaction.c b/src/process_transaction.c index b7c6b8e3..85d874e0 100644 --- a/src/process_transaction.c +++ b/src/process_transaction.c @@ -4,9 +4,10 @@ #include "pb_decode.h" #include "proto/protocol.pb.h" #include "swap_errors.h" -#include "reply_error.h" +#include "io.h" #include "base64.h" #include "pb_structs.h" +#include "globals.h" typedef struct currency_alias_s { const char *const foreign_name; @@ -50,7 +51,7 @@ void set_ledger_currency_name(char *currency, size_t currency_size) { * type consistency. */ -void trim_pb_bytes_array(pb_bytes_array_16_t *transaction) { +static void trim_pb_bytes_array(pb_bytes_array_16_t *transaction) { pb_size_t i; for (i = 0; i < transaction->size; i++) { if (transaction->bytes[i] != 0) { @@ -64,44 +65,46 @@ void trim_pb_bytes_array(pb_bytes_array_16_t *transaction) { memmove(transaction->bytes, transaction->bytes + i, transaction->size); } -void normalize_currencies(swap_app_context_t *ctx) { - to_uppercase(ctx->received_transaction.currency_from, - sizeof(ctx->received_transaction.currency_from)); - to_uppercase(ctx->received_transaction.currency_to, - sizeof(ctx->received_transaction.currency_to)); - set_ledger_currency_name(ctx->received_transaction.currency_from, - sizeof(ctx->received_transaction.currency_from) / - sizeof(ctx->received_transaction.currency_from[0])); - set_ledger_currency_name(ctx->received_transaction.currency_to, - sizeof(ctx->received_transaction.currency_to) / - sizeof(ctx->received_transaction.currency_to[0])); +static void normalize_currencies(void) { + to_uppercase(G_swap_ctx.received_transaction.currency_from, + sizeof(G_swap_ctx.received_transaction.currency_from)); + to_uppercase(G_swap_ctx.received_transaction.currency_to, + sizeof(G_swap_ctx.received_transaction.currency_to)); + set_ledger_currency_name(G_swap_ctx.received_transaction.currency_from, + sizeof(G_swap_ctx.received_transaction.currency_from) / + sizeof(G_swap_ctx.received_transaction.currency_from[0])); + set_ledger_currency_name(G_swap_ctx.received_transaction.currency_to, + sizeof(G_swap_ctx.received_transaction.currency_to) / + sizeof(G_swap_ctx.received_transaction.currency_to[0])); // triming leading 0s - trim_pb_bytes_array((pb_bytes_array_16_t *) &(ctx->received_transaction.amount_to_provider)); - trim_pb_bytes_array((pb_bytes_array_16_t *) &(ctx->received_transaction.amount_to_wallet)); + trim_pb_bytes_array( + (pb_bytes_array_16_t *) &(G_swap_ctx.received_transaction.amount_to_provider)); + trim_pb_bytes_array( + (pb_bytes_array_16_t *) &(G_swap_ctx.received_transaction.amount_to_wallet)); // strip bcash CashAddr header, and other bicmd->subcommand1 like headers - for (size_t i = 0; i < sizeof(ctx->received_transaction.payin_address); i++) { - if (ctx->received_transaction.payin_address[i] == ':') { - memmove(ctx->received_transaction.payin_address, - ctx->received_transaction.payin_address + i + 1, - sizeof(ctx->received_transaction.payin_address) - i - 1); + for (size_t i = 0; i < sizeof(G_swap_ctx.received_transaction.payin_address); i++) { + if (G_swap_ctx.received_transaction.payin_address[i] == ':') { + memmove(G_swap_ctx.received_transaction.payin_address, + G_swap_ctx.received_transaction.payin_address + i + 1, + sizeof(G_swap_ctx.received_transaction.payin_address) - i - 1); break; } } } -int process_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunction send) { +int process_transaction(const command_t *cmd) { if (cmd->data.size < 1) { PRINTF("Error: Can't parse process_transaction message, length should be more than 1\n"); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } size_t payload_length = cmd->data.bytes[0]; if (cmd->data.size < 1 + payload_length) { PRINTF("Error: Can't parse process_transaction message, invalid payload length\n"); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } pb_istream_t stream; @@ -117,29 +120,29 @@ int process_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunct if (!pb_decode(&stream, ledger_swap_NewTransactionResponse_fields, - &ctx->received_transaction)) { + &G_swap_ctx.received_transaction)) { PRINTF("Error: Can't parse SWAP transaction protobuf\n%.*H\n", payload_length, cmd->data.bytes + 1); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } - if (memcmp(ctx->device_transaction_id.swap, - ctx->received_transaction.device_transaction_id, - sizeof(ctx->device_transaction_id.swap)) != 0) { + if (memcmp(G_swap_ctx.device_transaction_id.swap, + G_swap_ctx.received_transaction.device_transaction_id, + sizeof(G_swap_ctx.device_transaction_id.swap)) != 0) { PRINTF( "Error: Device transaction IDs (SWAP) doesn't match. Expected: {%.*H}, got " "{%.*H}\n", - sizeof(ctx->device_transaction_id.swap), - ctx->device_transaction_id.swap, - sizeof(ctx->device_transaction_id.swap), - ctx->received_transaction.device_transaction_id); + sizeof(G_swap_ctx.device_transaction_id.swap), + G_swap_ctx.device_transaction_id.swap, + sizeof(G_swap_ctx.device_transaction_id.swap), + G_swap_ctx.received_transaction.device_transaction_id); - return reply_error(ctx, WRONG_TRANSACTION_ID, send); + return reply_error(WRONG_TRANSACTION_ID); } - normalize_currencies(ctx); + normalize_currencies(); } if (cmd->subcommand == SELL || cmd->subcommand == FUND) { @@ -156,7 +159,7 @@ int process_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunct if (n < 0) { PRINTF("Error: Can't decode SELL/FUND transaction base64\n"); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } PRINTF("decode_base64(payload): %.*H\n", n, payload); @@ -172,59 +175,59 @@ int process_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunct : ledger_swap_NewFundResponse_fields); if (cmd->subcommand == SELL) { - if (!pb_decode(&stream, pb_fields, &ctx->sell_transaction)) { + if (!pb_decode(&stream, pb_fields, &G_swap_ctx.sell_transaction)) { PRINTF("Error: Can't parse SELL transaction protobuf\n"); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } // Field not received from protobuf - ctx->sell_transaction_extra_id[0] = '\0'; + G_swap_ctx.sell_transaction_extra_id[0] = '\0'; } else { - if (!pb_decode(&stream, pb_fields, &ctx->fund_transaction)) { + if (!pb_decode(&stream, pb_fields, &G_swap_ctx.fund_transaction)) { PRINTF("Error: Can't parse FUND transaction protobuf\n"); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } // Field not received from protobuf - ctx->fund_transaction_extra_id[0] = '\0'; + G_swap_ctx.fund_transaction_extra_id[0] = '\0'; } // trim leading 0s pb_bytes_array_16_t *in_amount; - if (ctx->subcommand == SELL) { - in_amount = (pb_bytes_array_16_t *) &ctx->sell_transaction.in_amount; + if (G_swap_ctx.subcommand == SELL) { + in_amount = (pb_bytes_array_16_t *) &G_swap_ctx.sell_transaction.in_amount; } else { - in_amount = (pb_bytes_array_16_t *) &ctx->fund_transaction.in_amount; + in_amount = (pb_bytes_array_16_t *) &G_swap_ctx.fund_transaction.in_amount; } trim_pb_bytes_array(in_amount); pb_bytes_array_32_t *tx_id; - if (ctx->subcommand == SELL) { - tx_id = (pb_bytes_array_32_t *) &ctx->sell_transaction.device_transaction_id; - PRINTF("ctx->sell_transaction->device_transaction_id @%p: %.*H\n", - ctx->sell_transaction.device_transaction_id.bytes, - ctx->sell_transaction.device_transaction_id.size, - ctx->sell_transaction.device_transaction_id.bytes); + if (G_swap_ctx.subcommand == SELL) { + tx_id = (pb_bytes_array_32_t *) &G_swap_ctx.sell_transaction.device_transaction_id; + PRINTF("G_swap_ctx.sell_transaction->device_transaction_id @%p: %.*H\n", + G_swap_ctx.sell_transaction.device_transaction_id.bytes, + G_swap_ctx.sell_transaction.device_transaction_id.size, + G_swap_ctx.sell_transaction.device_transaction_id.bytes); } else { - tx_id = (pb_bytes_array_32_t *) &ctx->fund_transaction.device_transaction_id; - PRINTF("ctx->fund_transaction->device_transaction_id @%p: %.*H\n", - ctx->fund_transaction.device_transaction_id.bytes, - ctx->fund_transaction.device_transaction_id.size, - ctx->fund_transaction.device_transaction_id.bytes); + tx_id = (pb_bytes_array_32_t *) &G_swap_ctx.fund_transaction.device_transaction_id; + PRINTF("G_swap_ctx.fund_transaction->device_transaction_id @%p: %.*H\n", + G_swap_ctx.fund_transaction.device_transaction_id.bytes, + G_swap_ctx.fund_transaction.device_transaction_id.size, + G_swap_ctx.fund_transaction.device_transaction_id.bytes); } - if (tx_id->size != sizeof(ctx->device_transaction_id.sell_fund)) { + if (tx_id->size != sizeof(G_swap_ctx.device_transaction_id.sell_fund)) { PRINTF("Error: Device transaction ID (SELL/FUND) size doesn't match\n"); PRINTF("tx_id->size = %d\n", tx_id->size); - PRINTF("sizeof(ctx->device_transaction_id.sell_fund) = %d\n", - sizeof(ctx->device_transaction_id.sell_fund)); + PRINTF("sizeof(G_swap_ctx.device_transaction_id.sell_fund) = %d\n", + sizeof(G_swap_ctx.device_transaction_id.sell_fund)); } - if (memcmp(ctx->device_transaction_id.sell_fund, tx_id->bytes, tx_id->size) != 0) { + if (memcmp(G_swap_ctx.device_transaction_id.sell_fund, tx_id->bytes, tx_id->size) != 0) { PRINTF("Error: Device transaction IDs (SELL/FUND) don't match\n"); - PRINTF("ctx->device_transaction_id @%p: %.*H\n", - ctx->device_transaction_id.sell_fund, - sizeof(ctx->device_transaction_id.sell_fund), - ctx->device_transaction_id.sell_fund); + PRINTF("G_swap_ctx.device_transaction_id @%p: %.*H\n", + G_swap_ctx.device_transaction_id.sell_fund, + sizeof(G_swap_ctx.device_transaction_id.sell_fund), + G_swap_ctx.device_transaction_id.sell_fund); - return reply_error(ctx, WRONG_TRANSACTION_ID, send); + return reply_error(WRONG_TRANSACTION_ID); } } @@ -232,46 +235,46 @@ int process_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunct CX_LAST, cmd->data.bytes + 1, payload_length, - ctx->sha256_digest, - sizeof(ctx->sha256_digest)); + G_swap_ctx.sha256_digest, + sizeof(G_swap_ctx.sha256_digest)); - PRINTF("sha256_digest: %.*H\n", 32, ctx->sha256_digest); + PRINTF("sha256_digest: %.*H\n", 32, G_swap_ctx.sha256_digest); if (cmd->data.size < 1 + payload_length + 1) { PRINTF("Error: Can't parse process_transaction message, should include fee\n"); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } - ctx->transaction_fee_length = cmd->data.bytes[1 + payload_length]; + G_swap_ctx.transaction_fee_length = cmd->data.bytes[1 + payload_length]; - if (ctx->transaction_fee_length > sizeof(ctx->transaction_fee)) { + if (G_swap_ctx.transaction_fee_length > sizeof(G_swap_ctx.transaction_fee)) { PRINTF("Error: Transaction fee is to long\n"); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } - if (cmd->data.size < 1 + payload_length + 1 + ctx->transaction_fee_length) { + if (cmd->data.size < 1 + payload_length + 1 + G_swap_ctx.transaction_fee_length) { PRINTF("Error: Input buffer is too small"); - return reply_error(ctx, DESERIALIZATION_FAILED, send); + return reply_error(DESERIALIZATION_FAILED); } - memset(ctx->transaction_fee, 0, sizeof(ctx->transaction_fee)); - memcpy(ctx->transaction_fee, + memset(G_swap_ctx.transaction_fee, 0, sizeof(G_swap_ctx.transaction_fee)); + memcpy(G_swap_ctx.transaction_fee, cmd->data.bytes + 1 + payload_length + 1, - ctx->transaction_fee_length); - PRINTF("Transaction fees BE = %.*H\n", ctx->transaction_fee_length, ctx->transaction_fee); + G_swap_ctx.transaction_fee_length); + PRINTF("Transaction fees BE = %.*H\n", + G_swap_ctx.transaction_fee_length, + G_swap_ctx.transaction_fee); - unsigned char output_buffer[2] = {0x90, 0x00}; - - if (send(output_buffer, 2) < 0) { + if (reply_success() < 0) { PRINTF("Error: failed to send response\n"); return -1; } - ctx->state = TRANSACTION_RECEIVED; + G_swap_ctx.state = TRANSACTION_RECEIVED; return 0; } diff --git a/src/process_transaction.h b/src/process_transaction.h index d43b99a2..876b8375 100644 --- a/src/process_transaction.h +++ b/src/process_transaction.h @@ -1,10 +1,5 @@ -#ifndef _PROCESS_TRANSACTION_H_ -#define _PROCESS_TRANSACTION_H_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int process_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif // _PROCESS_TRANSACTION_H_ +int process_transaction(const command_t *cmd); diff --git a/src/reply_error.c b/src/reply_error.c deleted file mode 100644 index 0f0b3ec4..00000000 --- a/src/reply_error.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "reply_error.h" -#include "os.h" -#include "swap_errors.h" -#include "init.h" - -int reply_error(swap_app_context_t *ctx, swap_error_e error, SendFunction send) { - init_application_context(ctx); - unsigned char output_buffer[2] = {(error >> 8) & 0xFF, error & 0xFF}; - return send(output_buffer, 2); -} \ No newline at end of file diff --git a/src/reply_error.h b/src/reply_error.h deleted file mode 100644 index 3493c182..00000000 --- a/src/reply_error.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _REPLY_ERROR_H_ -#define _REPLY_ERROR_H_ - -#include "swap_app_context.h" -#include "send_function.h" -#include "swap_errors.h" - -// Send a error message, change the state to INITIAL -// return negative number in case of something go wrong (send operation for example) -int reply_error(swap_app_context_t *ctx, swap_error_e error, SendFunction send); - -#endif // _REPLY_ERROR_H_ \ No newline at end of file diff --git a/src/send_function.h b/src/send_function.h deleted file mode 100644 index bf9d2434..00000000 --- a/src/send_function.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SEND_FUNCTION_H_ -#define _SEND_FUNCTION_H_ - -typedef int (*SendFunction)(unsigned char *buffer_to_send, unsigned int buffer_length); - -#endif // _SEND_FUNCTION_H_ \ No newline at end of file diff --git a/src/set_partner_key.c b/src/set_partner_key.c index 3deff668..a007c1d3 100644 --- a/src/set_partner_key.c +++ b/src/set_partner_key.c @@ -1,13 +1,13 @@ #include #include -#include "swap_app_context.h" +#include "globals.h" #include "set_partner_key.h" #include "swap_errors.h" #include "globals.h" -#include "reply_error.h" +#include "io.h" -int set_partner_key(swap_app_context_t *ctx, const command_t *cmd, SendFunction send) { +int set_partner_key(const command_t *cmd) { // data is serialized as // 1 byte - partner name length L // L bytes - partner name @@ -15,56 +15,57 @@ int set_partner_key(swap_app_context_t *ctx, const command_t *cmd, SendFunction if (cmd->data.size < 1) { PRINTF("Error: Input buffer is too small\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } - ctx->partner.name_length = cmd->data.bytes[0]; + G_swap_ctx.partner.name_length = cmd->data.bytes[0]; - if ((ctx->partner.name_length < MIN_PARTNER_NAME_LENGHT) || - (ctx->partner.name_length > MAX_PARTNER_NAME_LENGHT)) { + if ((G_swap_ctx.partner.name_length < MIN_PARTNER_NAME_LENGHT) || + (G_swap_ctx.partner.name_length > MAX_PARTNER_NAME_LENGHT)) { PRINTF("Error: Partner name length should be in [%u, %u]\n", MIN_PARTNER_NAME_LENGHT, MAX_PARTNER_NAME_LENGHT); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } - if (1 + ctx->partner.name_length + UNCOMPRESSED_KEY_LENGTH != cmd->data.size) { + if (1 + G_swap_ctx.partner.name_length + UNCOMPRESSED_KEY_LENGTH != cmd->data.size) { PRINTF("Error: Input buffer length doesn't match correct SET_PARTNER_KEY message\n"); - return reply_error(ctx, INCORRECT_COMMAND_DATA, send); + return reply_error(INCORRECT_COMMAND_DATA); } // The incoming partner name is NOT NULL terminated, so we use memcpy and // manually NULL terminate the buffer - memset(ctx->partner.name, 0, sizeof(ctx->partner.name)); - memcpy(ctx->partner.name, cmd->data.bytes + 1, ctx->partner.name_length); + memset(G_swap_ctx.partner.name, 0, sizeof(G_swap_ctx.partner.name)); + memcpy(G_swap_ctx.partner.name, cmd->data.bytes + 1, G_swap_ctx.partner.name_length); if (cmd->subcommand == SWAP) { cx_ecfp_init_public_key(CX_CURVE_SECP256K1, - cmd->data.bytes + 1 + ctx->partner.name_length, + cmd->data.bytes + 1 + G_swap_ctx.partner.name_length, UNCOMPRESSED_KEY_LENGTH, - &(ctx->partner.public_key)); + &(G_swap_ctx.partner.public_key)); } if (cmd->subcommand == SELL || cmd->subcommand == FUND) { cx_ecfp_init_public_key(CX_CURVE_256R1, - cmd->data.bytes + 1 + ctx->partner.name_length, + cmd->data.bytes + 1 + G_swap_ctx.partner.name_length, UNCOMPRESSED_KEY_LENGTH, - &(ctx->partner.public_key)); + &(G_swap_ctx.partner.public_key)); } - cx_hash_sha256(cmd->data.bytes, cmd->data.size, ctx->sha256_digest, sizeof(ctx->sha256_digest)); - - unsigned char ouput_buffer[2] = {0x90, 0x00}; + cx_hash_sha256(cmd->data.bytes, + cmd->data.size, + G_swap_ctx.sha256_digest, + sizeof(G_swap_ctx.sha256_digest)); - if (send(ouput_buffer, 2) < 0) { + if (reply_success() < 0) { PRINTF("Error: failed to send\n"); return -1; } - ctx->state = PROVIDER_SET; + G_swap_ctx.state = PROVIDER_SET; return 0; } diff --git a/src/set_partner_key.h b/src/set_partner_key.h index 4e07609c..8fcf1b6d 100644 --- a/src/set_partner_key.h +++ b/src/set_partner_key.h @@ -1,10 +1,5 @@ -#ifndef _SET_PARTNER_KEY_H_ -#define _SET_PARTNER_KEY_H_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int set_partner_key(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif //_SET_PARTNER_KEY_H_ +int set_partner_key(const command_t *cmd); diff --git a/src/start_new_transaction.c b/src/start_new_transaction.c index 6b89a49a..d035adf8 100644 --- a/src/start_new_transaction.c +++ b/src/start_new_transaction.c @@ -2,30 +2,29 @@ #include "start_new_transaction.h" #include "init.h" -#include "reply_error.h" +#include "io.h" -int start_new_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunction send) { - unsigned char output_buffer[sizeof(ctx->device_transaction_id) + 2]; - unsigned int output_buffer_size = 0; +int start_new_transaction(const command_t *cmd) { + // prepare size for device_transaction_id + 0x9000 + uint8_t output_buffer[sizeof(G_swap_ctx.device_transaction_id) + 2]; + size_t output_buffer_size = 0; - init_application_context(ctx); + init_application_context(); if (cmd->subcommand == SWAP) { - output_buffer_size = sizeof(ctx->device_transaction_id.swap); + output_buffer_size = sizeof(G_swap_ctx.device_transaction_id.swap); for (unsigned int i = 0; i < output_buffer_size; ++i) { #ifdef TESTING - ctx->device_transaction_id.swap[i] = (char) ((int) 'A' + 42 % 26); - // uint8_t replay_id[] = {0x61, 0x71, 0x65, 0x75, 0x6c, 0x63, 0x68, 0x71, 0x65, 0x6b}; - // memcpy(ctx->device_transaction_id.swap, replay_id, sizeof(replay_id)); + G_swap_ctx.device_transaction_id.swap[i] = (char) ((int) 'A' + 42 % 26); #else - ctx->device_transaction_id.swap[i] = (char) ((int) 'A' + cx_rng_u8() % 26); + G_swap_ctx.device_transaction_id.swap[i] = (char) ((int) 'A' + cx_rng_u8() % 26); #endif } } if (cmd->subcommand == SELL || cmd->subcommand == FUND) { - output_buffer_size = sizeof(ctx->device_transaction_id.sell_fund); + output_buffer_size = sizeof(G_swap_ctx.device_transaction_id.sell_fund); #ifdef TESTING unsigned char tx_id[32] = { @@ -34,13 +33,13 @@ int start_new_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFun 0x23, 0x80, 0x1b, 0x1a, 0xeb, 0x7d, 0x0b, 0xcb, // 0xba, 0xa2, 0xa4, 0xf4, 0x6b, 0xf8, 0x18, 0x4b // }; - memcpy(ctx->device_transaction_id.sell_fund, tx_id, sizeof(tx_id)); + memcpy(G_swap_ctx.device_transaction_id.sell_fund, tx_id, sizeof(tx_id)); #else - cx_rng(ctx->device_transaction_id.sell_fund, output_buffer_size); + cx_rng(G_swap_ctx.device_transaction_id.sell_fund, output_buffer_size); #endif } - memcpy(output_buffer, &ctx->device_transaction_id, output_buffer_size); + memcpy(output_buffer, &G_swap_ctx.device_transaction_id, output_buffer_size); // TODO: add extra sw args for send() and skip status word set in each caller output_buffer[output_buffer_size] = 0x90; @@ -48,13 +47,14 @@ int start_new_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFun output_buffer_size += 2; - if (send(output_buffer, output_buffer_size) < 0) { + if (send_apdu(output_buffer, output_buffer_size) < 0) { PRINTF("Error: failed to send"); return -1; } - ctx->state = WAITING_TRANSACTION; - ctx->subcommand = cmd->subcommand; + G_swap_ctx.state = WAITING_TRANSACTION; + G_swap_ctx.subcommand = cmd->subcommand; + G_swap_ctx.rate = cmd->rate; return 0; } diff --git a/src/start_new_transaction.h b/src/start_new_transaction.h index 92f526a5..1082d85f 100644 --- a/src/start_new_transaction.h +++ b/src/start_new_transaction.h @@ -1,10 +1,5 @@ -#ifndef _START_NEW_TRANSACTION_H_ -#define _START_NEW_TRANSACTION_H_ +#pragma once -#include "swap_app_context.h" -#include "send_function.h" #include "commands.h" -int start_new_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif //_START_NEW_TRANSACTION_H_ +int start_new_transaction(const command_t *cmd); diff --git a/src/start_signing_transaction.c b/src/start_signing_transaction.c index fd065316..c290fd74 100644 --- a/src/start_signing_transaction.c +++ b/src/start_signing_transaction.c @@ -1,45 +1,45 @@ #include "start_signing_transaction.h" #include "currency_lib_calls.h" -#include "reply_error.h" +#include "globals.h" +#include "io.h" -int start_signing_transaction(swap_app_context_t *ctx, - const command_t *cmd, - __attribute__((unused)) SendFunction send) { +int start_signing_transaction(const command_t *cmd) { G_io_apdu_buffer[0] = 0x90; G_io_apdu_buffer[1] = 0x00; io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); - ctx->state = INITIAL_STATE; + G_swap_ctx.state = INITIAL_STATE; static create_transaction_parameters_t lib_in_out_params; - lib_in_out_params.fee_amount = ctx->transaction_fee; - lib_in_out_params.fee_amount_length = ctx->transaction_fee_length; - lib_in_out_params.coin_configuration = ctx->payin_coin_config.bytes; - lib_in_out_params.coin_configuration_length = ctx->payin_coin_config.size; + lib_in_out_params.fee_amount = G_swap_ctx.transaction_fee; + lib_in_out_params.fee_amount_length = G_swap_ctx.transaction_fee_length; + lib_in_out_params.coin_configuration = G_swap_ctx.payin_coin_config.bytes; + lib_in_out_params.coin_configuration_length = G_swap_ctx.payin_coin_config.size; if (cmd->subcommand == SWAP) { - lib_in_out_params.amount = ctx->received_transaction.amount_to_provider.bytes; - lib_in_out_params.amount_length = ctx->received_transaction.amount_to_provider.size; - lib_in_out_params.destination_address = ctx->received_transaction.payin_address; - lib_in_out_params.destination_address_extra_id = ctx->received_transaction.payin_extra_id; + lib_in_out_params.amount = G_swap_ctx.received_transaction.amount_to_provider.bytes; + lib_in_out_params.amount_length = G_swap_ctx.received_transaction.amount_to_provider.size; + lib_in_out_params.destination_address = G_swap_ctx.received_transaction.payin_address; + lib_in_out_params.destination_address_extra_id = + G_swap_ctx.received_transaction.payin_extra_id; } if (cmd->subcommand == SELL) { - lib_in_out_params.amount = ctx->sell_transaction.in_amount.bytes; - lib_in_out_params.amount_length = ctx->sell_transaction.in_amount.size; - lib_in_out_params.destination_address = ctx->sell_transaction.in_address; + lib_in_out_params.amount = G_swap_ctx.sell_transaction.in_amount.bytes; + lib_in_out_params.amount_length = G_swap_ctx.sell_transaction.in_amount.size; + lib_in_out_params.destination_address = G_swap_ctx.sell_transaction.in_address; // Empty string, needed by application library API but does not have sense in SELL context - lib_in_out_params.destination_address_extra_id = ctx->sell_transaction_extra_id; + lib_in_out_params.destination_address_extra_id = G_swap_ctx.sell_transaction_extra_id; } if (cmd->subcommand == FUND) { - lib_in_out_params.amount = ctx->fund_transaction.in_amount.bytes; - lib_in_out_params.amount_length = ctx->fund_transaction.in_amount.size; - lib_in_out_params.destination_address = ctx->fund_transaction.in_address; + lib_in_out_params.amount = G_swap_ctx.fund_transaction.in_amount.bytes; + lib_in_out_params.amount_length = G_swap_ctx.fund_transaction.in_amount.size; + lib_in_out_params.destination_address = G_swap_ctx.fund_transaction.in_address; // Empty string, needed by application library API but does not have sense in FUND context - lib_in_out_params.destination_address_extra_id = ctx->fund_transaction_extra_id; + lib_in_out_params.destination_address_extra_id = G_swap_ctx.fund_transaction_extra_id; } - create_payin_transaction(ctx->payin_binary_name, &lib_in_out_params); + create_payin_transaction(G_swap_ctx.payin_binary_name, &lib_in_out_params); return 0; } diff --git a/src/start_signing_transaction.h b/src/start_signing_transaction.h index 52fc2ad3..7dab13d0 100644 --- a/src/start_signing_transaction.h +++ b/src/start_signing_transaction.h @@ -1,11 +1,5 @@ -#ifndef _START_SIGNING_TRANSACTION_H_ -#define _START_SIGNING_TRANSACTION_H_ +#pragma once -#include "send_function.h" -#include "swap_app_context.h" #include "commands.h" -#include "buffer.h" -int start_signing_transaction(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif //_START_SIGNING_TRANSACTION_H_ +int start_signing_transaction(const command_t *cmd); diff --git a/src/swap_app_context.h b/src/swap_app_context.h deleted file mode 100644 index d4aa2e77..00000000 --- a/src/swap_app_context.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _SWAP_APP_CONTEXT_H_ -#define _SWAP_APP_CONTEXT_H_ - -#include - -#include "states.h" -#include "proto/protocol.pb.h" -#include "commands.h" -#include "globals.h" -#include "buffer.h" - -#define MIN_PARTNER_NAME_LENGHT 3 -#define MAX_PARTNER_NAME_LENGHT 15 - -typedef struct partner_data_s { - unsigned char name_length; - char name[MAX_PARTNER_NAME_LENGHT + 1]; - cx_ecfp_256_public_key_t public_key; -} partner_data_t; - -typedef struct swap_app_context_s { - union { - unsigned char sell_fund[32]; // device_transaction_id (SELL && FUND) - char swap[10]; // device_transaction_id (SWAP) - } device_transaction_id; - - unsigned char transaction_fee[16]; - unsigned char transaction_fee_length; - - partner_data_t partner; - state_e state; - subcommand_e subcommand; - - // SWAP, SELL, and FUND flows are unionized as they cannot be used in the same context - union { - ledger_swap_NewTransactionResponse received_transaction; - struct { - ledger_swap_NewSellResponse sell_transaction; - // Field not received from protobuf but needed by the application called as lib - char sell_transaction_extra_id[1]; - }; - struct { - ledger_swap_NewFundResponse fund_transaction; - // Field not received from protobuf but needed by the application called as lib - char fund_transaction_extra_id[1]; - }; - }; - - unsigned char sha256_digest[32]; - - cx_ecfp_256_public_key_t ledger_public_key; - - buf_t payin_coin_config; // serialized coin configuration - char payin_binary_name[16]; - - char printable_get_amount[MAX_PRINTABLE_AMOUNT_SIZE]; -} swap_app_context_t; - -extern swap_app_context_t swap_ctx; - -#endif // _SWAP_APP_CONTEXT_H_ diff --git a/src/ui/menu.h b/src/ui/menu.h new file mode 100644 index 00000000..b78cf023 --- /dev/null +++ b/src/ui/menu.h @@ -0,0 +1,3 @@ +#pragma once + +void ui_idle(void); diff --git a/src/ui/menu_bagl.c b/src/ui/menu_bagl.c new file mode 100644 index 00000000..b3e68774 --- /dev/null +++ b/src/ui/menu_bagl.c @@ -0,0 +1,43 @@ +#ifdef HAVE_BAGL + +#include "menu.h" +#include "ux.h" +#include "os.h" +#include "globals.h" +#include "glyphs.h" +#include "io.h" +#include "commands.h" + +// clang-format off +UX_STEP_NOCB(ux_idle_flow_1_step, nn, +{ + "Exchange", + "is ready", +}); +UX_STEP_NOCB(ux_idle_flow_2_step, bn, +{ + "Version", + APPVERSION, +}); +UX_STEP_VALID(ux_idle_flow_3_step, pb, os_sched_exit(-1), +{ + &C_icon_dashboard_x, + "Quit", +}); + +UX_FLOW(ux_idle_flow, + &ux_idle_flow_1_step, + &ux_idle_flow_2_step, + &ux_idle_flow_3_step, + FLOW_LOOP); +// clang-format on + +void ui_idle(void) { + // reserve a display stack slot if none yet + if (G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_idle_flow, NULL); +} + +#endif // HAVE_BAGL diff --git a/src/ui/validate_transaction.h b/src/ui/validate_transaction.h new file mode 100644 index 00000000..e08eb806 --- /dev/null +++ b/src/ui/validate_transaction.h @@ -0,0 +1,3 @@ +#pragma once + +void ui_validate_amounts(void); diff --git a/src/ui/validate_transaction_bagl.c b/src/ui/validate_transaction_bagl.c new file mode 100644 index 00000000..23bf9aac --- /dev/null +++ b/src/ui/validate_transaction_bagl.c @@ -0,0 +1,110 @@ +#ifdef HAVE_BAGL + +#include "menu.h" +#include "validate_transaction.h" +#include "ux.h" +#include "os.h" +#include "globals.h" +#include "glyphs.h" +#include "io.h" +#include "commands.h" + +static void on_accept(__attribute__((unused)) const bagl_element_t *e) { + reply_success(); + G_swap_ctx.state = WAITING_SIGNING; + ui_idle(); +} + +static void on_reject(__attribute__((unused)) const bagl_element_t *e) { + PRINTF("User refused transaction\n"); + reply_error(USER_REFUSED); + ui_idle(); +} + +// clang-format off +UX_STEP_NOCB(ux_confirm_flow_1_step, pnn, +{ + &C_icon_eye, + "Review", + "transaction", +}); +UX_STEP_NOCB(ux_confirm_flow_1_2_step, bnnn_paging, +{ + .title = "Email", + .text = G_swap_ctx.sell_transaction.trader_email, +}); +UX_STEP_NOCB(ux_confirm_flow_1_3_step, bnnn_paging, +{ + .title = "User", + .text = G_swap_ctx.fund_transaction.user_id, +}); +UX_STEP_NOCB(ux_confirm_flow_2_step, bnnn_paging, +{ + .title = "Send", + .text = G_swap_ctx.printable_send_amount, +}); +UX_STEP_NOCB(ux_confirm_flow_3_step, bnnn_paging, +{ + .title = "Get", + .text = G_swap_ctx.printable_get_amount, +}); +UX_STEP_NOCB(ux_confirm_flow_3_floating_step, bnnn_paging, +{ + .title = "Get estimated", + .text = G_swap_ctx.printable_get_amount, +}); +UX_STEP_NOCB(ux_confirm_flow_3_2_step, bnnn_paging, +{ + .title = G_swap_ctx.partner.prefixed_name, + .text = G_swap_ctx.printable_get_amount, +}); +UX_STEP_NOCB(ux_confirm_flow_4_step, bnnn_paging, +{ + .title = "Fees", + .text = G_swap_ctx.printable_fees_amount, +}); +UX_STEP_CB(ux_confirm_flow_5_step, pbb, on_accept(NULL), +{ + &C_icon_validate_14, + "Accept", + "and send", +}); +UX_STEP_CB(ux_confirm_flow_6_step, pb, on_reject(NULL), +{ + &C_icon_crossmark, + "Reject", +}); + +// clang-format on +const ux_flow_step_t *ux_confirm_flow[8]; + +void ui_validate_amounts(void) { + int step = 0; + + ux_confirm_flow[step++] = &ux_confirm_flow_1_step; + + if (G_swap_ctx.subcommand == SELL) { + ux_confirm_flow[step++] = &ux_confirm_flow_1_2_step; + } else if (G_swap_ctx.subcommand == FUND) { + ux_confirm_flow[step++] = &ux_confirm_flow_1_3_step; + } + + ux_confirm_flow[step++] = &ux_confirm_flow_2_step; + + if (G_swap_ctx.subcommand == FUND) { + ux_confirm_flow[step++] = &ux_confirm_flow_3_2_step; + } else if (G_swap_ctx.rate == FLOATING) { + ux_confirm_flow[step++] = &ux_confirm_flow_3_floating_step; + } else { + ux_confirm_flow[step++] = &ux_confirm_flow_3_step; + } + + ux_confirm_flow[step++] = &ux_confirm_flow_4_step; + ux_confirm_flow[step++] = &ux_confirm_flow_5_step; + ux_confirm_flow[step++] = &ux_confirm_flow_6_step; + ux_confirm_flow[step++] = FLOW_END_STEP; + + ux_flow_init(0, ux_confirm_flow, NULL); +} + +#endif diff --git a/src/unexpected_command.c b/src/unexpected_command.c deleted file mode 100644 index 87627c5a..00000000 --- a/src/unexpected_command.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "unexpected_command.h" -#include "reply_error.h" -#include "swap_errors.h" - -int unexpected_command(swap_app_context_t *ctx, - __attribute__((unused)) const command_t *cmd, - SendFunction send) { - return reply_error(ctx, INVALID_INSTRUCTION, send); -} diff --git a/src/unexpected_command.h b/src/unexpected_command.h deleted file mode 100644 index 66315d86..00000000 --- a/src/unexpected_command.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _UNEXPECTED_COMMAND_H_ -#define _UNEXPECTED_COMMAND_H_ - -#include "swap_app_context.h" -#include "send_function.h" -#include "commands.h" - -int unexpected_command(swap_app_context_t *ctx, const command_t *cmd, SendFunction send); - -#endif //_UNEXPECTED_COMMAND_H_