What changed, and why it matters
This commit refactors the Ledger Bitcoin app to use the newer Ledger SDK 'standard app' framework for main I/O loops and swap (exchange) integration. It removes a lot of custom boilerplate code and replaces it with SDK-provided equivalents. The change also enables the SWAP feature by default in the Makefile. There is no direct evidence in the diff of a security vulnerability being fixed; it appears to be a modernization and code-cleanup change. However, because it touches core app lifecycle, I/O, and swap handling code, any mistake in the transition could affect app stability or swap security.
Treat this as a high-touch refactor requiring careful review and regression testing, especially for swap flows, APDU handling, device lifecycle (power/USB/BLE), and the removal of custom I/O functions. Verify that the SDK standard-app replacements preserve the same security invariants (e.g., timeout behavior, exception handling, swap isolation, mainnet AUTOAPPROVE guards). No immediate security patch action is indicated by the diff alone, but validation is warranted before release.
Security signals we found
Large refactor of application lifecycle and I/O event handling
Swap feature enabled by default (ENABLE_SWAP = 1)
Removal of custom io_event and io_exchange_al implementations
Migration from custom globals.h to SDK standard-app globals
Change in APDU error path: BAD LENGTH now continues loop instead of returning
Removal of HAVE_APPLICATION_FLAG_* block reordering and AUTOAPPROVE_FOR_PERF_TESTS guard consolidation
Evidence from the diff
The commit ‘main, io, swap standardization’ restructures the Ledger Bitcoin app build and runtime: Makefile now includes the SDK’s Makefile.target, removes DISABLE_STANDARD_APP_FILES/DISABLE_DEFAULT_IO_SEPROXY_BUFFER_SIZE, deletes manual inclusion of lib_standard_app source files, and enables ENABLE_SWAP. The custom main()/coin_main()/swap_library_main() lifecycle, io_event(), and io_exchange_al() implementations in src/main.c and src/boilerplate/io_ext.c are removed or replaced with SDK standard-app equivalents (io_init, io_recv_command, app_ticker_event_callback). Globals such as G_io_seproxyhal_spi_buffer, G_ux, G_ux_params, and G_output_len are moved from a local globals.h to SDK-provided headers. Swap handlers are renamed to swap_* and now use SDK swap_lib_calls.h/swap.h. The swap global called_from_swap is replaced by the SDK’s G_called_from_swap. Error handling in app_main now continues on bad APDU length instead of returning, and logging is cleaned up.
Changed components
src/main.csrc/boilerplate/io_ext.csrc/boilerplate/io_ext.hsrc/boilerplate/dispatcher.csrc/globals.hsrc/handler/get_wallet_address.csrc/handler/sign_psbt.csrc/handler/sign_psbt/musig_signing.csrc/swap/handle_check_address.csrc/swap/handle_check_address.hsrc/swap/handle_get_printable_amount.csrc/swap/handle_get_printable_amount.hsrc/swap/handle_swap_sign_transaction.csrc/swap/handle_swap_sign_transaction.hsrc/swap/swap_globals.hsrc/ui/display.hsrc/ui/menu_nbgl.cMakefileInspect captured patch +155 / −426
diff --git a/Makefile b/Makefile
index cbe63d0..81b59d2 100644
--- a/Makefile
+++ b/Makefile
@@ -19,11 +19,11 @@ ifeq ($(BOLOS_SDK),)
$(error Environment variable BOLOS_SDK is not set)
endif
-# Application allowed derivation curves.
-CURVE_APP_LOAD_PARAMS = secp256k1
+include $(BOLOS_SDK)/Makefile.target
-# Allowed SLIP21 paths
-PATH_SLIP21_APP_LOAD_PARAMS = "LEDGER-Wallet policy"
+########################################
+# Mandatory configuration #
+########################################
# Application version
APPVERSION_M = 2
@@ -37,12 +37,22 @@ else
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-$(strip $(APPVERSION_SUFFIX))"
endif
-# If set, the app will automatically approve all requests without user interaction. Useful for performance tests.
-# It is critical that no such app is ever deployed in production.
-AUTOAPPROVE_FOR_PERF_TESTS ?= 0
-ifneq ($(AUTOAPPROVE_FOR_PERF_TESTS),0)
- DEFINES += HAVE_AUTOAPPROVE_FOR_PERF_TESTS
-endif
+# Application source files
+APP_SOURCE_PATH += src
+
+# Application icons following guidelines:
+# https://developers.ledger.com/docs/embedded-app/design-requirements/#device-icon
+ICON_NANOX = icons/nanox_app_bitcoin.gif
+ICON_NANOSP = icons/nanox_app_bitcoin.gif
+ICON_STAX = icons/stax_app_bitcoin.gif
+ICON_FLEX = icons/flex_app_bitcoin.gif
+ICON_APEX_P = icons/apex_p_app_bitcoin.png
+
+# Application allowed derivation curves.
+CURVE_APP_LOAD_PARAMS = secp256k1
+
+# Allowed SLIP21 paths
+PATH_SLIP21_APP_LOAD_PARAMS = "LEDGER-Wallet policy"
# Setting to allow building variant applications
VARIANT_PARAM = COIN
@@ -53,17 +63,8 @@ ifndef COIN
COIN=bitcoin_testnet
endif
-########################################
-# Application custom permissions #
-########################################
-HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1
-HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1
-HAVE_APPLICATION_FLAG_LIBRARY = 1
-
+# Coin-specific configuration
ifeq ($(COIN),bitcoin_testnet)
- # Application allowed derivation paths (testnet) + exception for Electrum + BIP-45 whole tree
- PATH_APP_LOAD_PARAMS = "*/1'" "4541509'" "45'"
-
# Bitcoin testnet, no legacy support
DEFINES += BIP32_PUBKEY_VERSION=0x043587CF
DEFINES += BIP44_COIN_TYPE=1
@@ -71,19 +72,11 @@ ifeq ($(COIN),bitcoin_testnet)
DEFINES += COIN_P2SH_VERSION=196
DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"tb\"
DEFINES += COIN_COINID_SHORT=\"TEST\"
-
APPNAME = "Bitcoin Test"
+ # Application allowed derivation paths (testnet) + exception for Electrum + BIP-45 whole tree
+ PATH_APP_LOAD_PARAMS = "*/1'" "4541509'" "45'"
else ifeq ($(COIN),bitcoin)
- # Application allowed derivation paths (mainnet) + exception for Electrum + BIP-45 whole tree
- PATH_APP_LOAD_PARAMS = "*/0'" "4541509'" "45'"
-
- # the version for performance tests automatically approves all requests
- # there is no reason to ever compile the mainnet app with this flag
- ifneq ($(AUTOAPPROVE_FOR_PERF_TESTS),0)
- $(error Use testnet app for performance tests)
- endif
-
# Bitcoin mainnet, no legacy support
DEFINES += BIP32_PUBKEY_VERSION=0x0488B21E
DEFINES += BIP44_COIN_TYPE=0
@@ -91,20 +84,11 @@ else ifeq ($(COIN),bitcoin)
DEFINES += COIN_P2SH_VERSION=5
DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"bc\"
DEFINES += COIN_COINID_SHORT=\"BTC\"
-
APPNAME = "Bitcoin"
+ # Application allowed derivation paths (mainnet) + exception for Electrum + BIP-45 whole tree
+ PATH_APP_LOAD_PARAMS = "*/0'" "4541509'" "45'"
else ifeq ($(COIN),bitcoin_recovery)
- # Application allowed derivation paths (all paths are permitted).
- PATH_APP_LOAD_PARAMS = ""
- HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1
-
- # the version for performance tests automatically approves all requests
- # there is no reason to ever compile the mainnet app with this flag
- ifneq ($(AUTOAPPROVE_FOR_PERF_TESTS),0)
- $(error Use testnet app for performance tests)
- endif
-
# Bitcoin mainnet, no legacy support
DEFINES += BIP32_PUBKEY_VERSION=0x0488B21E
DEFINES += BIP44_COIN_TYPE=0
@@ -113,8 +97,10 @@ else ifeq ($(COIN),bitcoin_recovery)
DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"bc\"
DEFINES += COIN_COINID_SHORT=\"BTC\"
DEFINES += BITCOIN_RECOVERY
-
APPNAME = "Bitcoin Recovery"
+ # Application allowed derivation paths (all paths are permitted).
+ PATH_APP_LOAD_PARAMS = ""
+ HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1
else
ifeq ($(filter clean,$(MAKECMDGOALS)),)
@@ -128,40 +114,64 @@ ifneq (,$(filter-out clean,$(MAKECMDGOALS)))
endif
endif
-ENABLE_NBGL_FOR_NANO_DEVICES = 1
-
-# Application icons following guidelines:
-# https://developers.ledger.com/docs/embedded-app/design-requirements/#device-icon
-ICON_NANOX = icons/nanox_app_bitcoin.gif
-ICON_NANOSP = icons/nanox_app_bitcoin.gif
-ICON_STAX = icons/stax_app_bitcoin.gif
-ICON_FLEX = icons/flex_app_bitcoin.gif
-ICON_APEX_P = icons/apex_p_app_bitcoin.png
+########################################
+# Application custom permissions #
+########################################
+# See SDK `include/appflags.h` for the purpose of each permission
+HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1
+HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1
+HAVE_APPLICATION_FLAG_LIBRARY = 1
########################################
# Application communication interfaces #
########################################
ENABLE_BLUETOOTH = 1
+ENABLE_NBGL_FOR_NANO_DEVICES = 1
########################################
# NBGL custom features #
########################################
ENABLE_NBGL_QRCODE = 1
+########################################
+# SWAP FEATURE FLAG #
+# This flag enables the swap feature #
+# in the Boilerplate application. #
+########################################
+# Testing only SWAP flag
+# ENABLE_TESTING_SWAP = 1
+# Production enabled SWAP flag
+ENABLE_SWAP = 1
+
########################################
# Features disablers #
########################################
# Don't use standard app file to avoid conflicts for now
-DISABLE_STANDARD_APP_FILES = 1
+#DISABLE_STANDARD_APP_FILES = 1
# Don't use default IO_SEPROXY_BUFFER_SIZE to use another
# value for NANOS for an unknown reason.
-DISABLE_DEFAULT_IO_SEPROXY_BUFFER_SIZE = 1
+#DISABLE_DEFAULT_IO_SEPROXY_BUFFER_SIZE = 1
+########################################
+# Application defines #
+########################################
DEFINES += HAVE_BOLOS_APP_STACK_CANARY
-
-DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300
+# If set, the app will automatically approve all requests without user interaction. Useful for performance tests.
+# It is critical that no such app is ever deployed in production.
+AUTOAPPROVE_FOR_PERF_TESTS ?= 0
+ifneq ($(AUTOAPPROVE_FOR_PERF_TESTS),0)
+ DEFINES += HAVE_AUTOAPPROVE_FOR_PERF_TESTS
+ # the version for performance tests automatically approves all requests
+ # there is no reason to ever compile the mainnet app with this flag
+ ifeq ($(COIN),bitcoin)
+ $(error Use testnet app for performance tests)
+ endif
+ ifeq ($(COIN),bitcoin_recovery)
+ $(error Use testnet app for performance tests)
+ endif
+endif
# debugging helper functions and macros
CFLAGS += -include debug-helpers/debug.h
@@ -175,21 +185,6 @@ endif
# Needed to be able to include the definition of G_cx
INCLUDES_PATH += $(BOLOS_SDK)/lib_cxng/src
-INCLUDES_PATH += $(BOLOS_SDK)/lib_standard_app
-
-# Application source files
-APP_SOURCE_PATH += src
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/base58.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/bip32.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/buffer.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/format.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/parser.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/read.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/varint.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/write.c
-
-# Allow usage of function from lib_standard_app/crypto_helpers.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/crypto_helpers.c
########################################
# Features enablers #
diff --git a/src/boilerplate/dispatcher.c b/src/boilerplate/dispatcher.c
index da9ff6c..8f17279 100644
--- a/src/boilerplate/dispatcher.c
+++ b/src/boilerplate/dispatcher.c
@@ -22,10 +22,10 @@
/* SDK headers */
#include "buffer.h"
+#include "io.h"
/* Local headers */
#include "constants.h"
-#include "globals.h"
#include "io_ext.h"
#include "sw.h"
diff --git a/src/boilerplate/io_ext.c b/src/boilerplate/io_ext.c
index 1f14db4..bb72c33 100644
--- a/src/boilerplate/io_ext.c
+++ b/src/boilerplate/io_ext.c
@@ -25,13 +25,13 @@
#include "nbgl_touch.h"
#include "nbgl_use_case.h"
#include "os.h"
+#include "swap.h"
#include "ux.h"
#include "write.h"
/* Local headers */
#include "dispatcher.h"
#include "display.h"
-#include "globals.h"
#include "sw.h"
#include "swap_globals.h"
@@ -80,89 +80,32 @@ void io_reset_timeouts() {
void io_show_processing_screen() {
if (!G_was_processing_screen_shown) {
G_was_processing_screen_shown = true;
- if (!G_swap_state.called_from_swap) {
+ if (!G_called_from_swap) {
nbgl_useCaseSpinner(ui_get_processing_screen_text());
}
}
}
-uint8_t io_event(uint8_t channel) {
- UNUSED(channel);
-
- switch (G_io_seproxyhal_spi_buffer[0]) {
- 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);
- }
- __attribute__((fallthrough));
- case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
- UX_DEFAULT_EVENT();
- break;
-#ifdef SCREEN_SIZE_WALLET
- case SEPROXYHAL_TAG_FINGER_EVENT:
- UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
- break;
-#endif // SCREEN_SIZE_WALLET
- case SEPROXYHAL_TAG_TICKER_EVENT:
- ++G_ticks;
-
- if (G_is_timeout_active.processing &&
- G_ticks - G_processing_timeout_start_tick >= PROCESSING_TIMEOUT_TICKS) {
- io_clear_processing_timeout();
-
- io_show_processing_screen();
- }
-
- if (G_is_timeout_active.interruption &&
- G_ticks - G_interruption_timeout_start_tick >= INTERRUPTION_TIMEOUT_TICKS) {
- io_clear_interruption_timeout();
-
- // TODO: It would be better to have the dispatcher be notified somehow.
- // This would require some tampering with the io_exchange in
- // process_interruption.
- THROW(EXCEPTION_IO_RESET);
- }
-
- UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {});
- break;
- default:
- UX_DEFAULT_EVENT();
- break;
- }
+// This function can be used to declare a callback to SEPROXYHAL_TAG_TICKER_EVENT in the application
+void app_ticker_event_callback(void) {
+ ++G_ticks;
+
+ if (G_is_timeout_active.processing &&
+ (uint16_t) (G_ticks - G_processing_timeout_start_tick) >= PROCESSING_TIMEOUT_TICKS) {
+ io_clear_processing_timeout();
- if (!io_seproxyhal_spi_is_status_sent()) {
- io_seproxyhal_general_status();
+ io_show_processing_screen();
}
- return 1;
-}
+ if (G_is_timeout_active.interruption &&
+ (uint16_t) (G_ticks - G_interruption_timeout_start_tick) >= INTERRUPTION_TIMEOUT_TICKS) {
+ io_clear_interruption_timeout();
-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);
+ // TODO: It would be better to have the dispatcher be notified somehow.
+ // This would require some tampering with the io_exchange in
+ // process_interruption.
+ THROW(EXCEPTION_IO_RESET);
}
-
- return 0;
}
void io_add_to_response(const void *rdata, size_t rdata_len) {
diff --git a/src/boilerplate/io_ext.h b/src/boilerplate/io_ext.h
index d4ab46b..997fa6d 100644
--- a/src/boilerplate/io_ext.h
+++ b/src/boilerplate/io_ext.h
@@ -9,6 +9,11 @@
/* Local headers */
#include "os_io_seproxyhal.h"
+/**
+ * Global variable with the length of APDU response to send back.
+ */
+extern uint16_t G_output_len;
+
/**
* IO callback called when an interrupt based channel has received
* data to be processed.
diff --git a/src/globals.h b/src/globals.h
deleted file mode 100644
index 34e1b79..0000000
--- a/src/globals.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-
-/* SDK headers */
-#include "ux.h"
-
-/* Local headers */
-#include "commands.h"
-#include "constants.h"
-#include "io_ext.h"
-
-/**
- * Global buffer for interactions between SE and MCU.
- */
-extern uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
-
-/**
- * Global variable with the length of APDU response to send back.
- */
-extern uint16_t G_output_len;
-
-/**
- * Global structure to perform asynchronous UX aside IO operations.
- */
-extern ux_state_t G_ux;
-
-/**
- * Global structure with the parameters to exchange with the BOLOS UX application.
- */
-extern bolos_ux_params_t G_ux_params;
diff --git a/src/handler/get_wallet_address.c b/src/handler/get_wallet_address.c
index 6da86b2..71364a3 100644
--- a/src/handler/get_wallet_address.c
+++ b/src/handler/get_wallet_address.c
@@ -22,6 +22,7 @@
#include "bip32.h"
#include "buffer.h"
#include "read.h"
+#include "swap.h"
/* Local headers */
#include "client_commands.h"
@@ -155,7 +156,7 @@ void handler_get_wallet_address(dispatcher_context_t *dc, uint8_t protocol_versi
}
// Swap feature: check that the wallet policy is a default one
- if (G_swap_state.called_from_swap && !is_wallet_default) {
+ if (G_called_from_swap && !is_wallet_default) {
PRINTF("Must be a default wallet policy for swap feature\n");
SEND_SW_EC(dc, SW_FAIL_SWAP, EC_SWAP_ERROR_WRONG_METHOD_NONDEFAULT_POLICY);
finalize_exchange_sign_transaction(false);
diff --git a/src/handler/sign_psbt.c b/src/handler/sign_psbt.c
index a1401cc..1bc017c 100644
--- a/src/handler/sign_psbt.c
+++ b/src/handler/sign_psbt.c
@@ -23,6 +23,7 @@
/* SDK headers */
#include "crypto_helpers.h"
#include "read.h"
+#include "swap.h"
#include "varint.h"
#include "write.h"
@@ -2170,7 +2171,7 @@ void handler_sign_psbt(dispatcher_context_t *dc, uint8_t protocol_version) {
// we execute the signing flow only if we're expected to produce any signature
// (including, possibly, any MuSig2 partial signature from Round 2 of MuSig2)
if (!only_signing_for_musig || st.has_musig2_pub_nonces) {
- if (G_swap_state.called_from_swap) {
+ if (G_called_from_swap) {
/** SWAP CHECKS
*
* If called from the exchange app, perform the necessary additional checks.
@@ -2196,7 +2197,7 @@ void handler_sign_psbt(dispatcher_context_t *dc, uint8_t protocol_version) {
*/
int sign_result = sign_transaction(dc, &st, cache, &signing_state, internal_inputs);
- if (!G_swap_state.called_from_swap) {
+ if (!G_called_from_swap) {
ui_post_processing_confirm_transaction(dc, sign_result);
}
@@ -2205,7 +2206,7 @@ void handler_sign_psbt(dispatcher_context_t *dc, uint8_t protocol_version) {
}
// Only if called from swap, the app should terminate after sending the response
- if (G_swap_state.called_from_swap) {
+ if (G_called_from_swap) {
G_swap_state.should_exit = true;
}
}
diff --git a/src/handler/sign_psbt/musig_signing.c b/src/handler/sign_psbt/musig_signing.c
index 896d1bc..122665e 100644
--- a/src/handler/sign_psbt/musig_signing.c
+++ b/src/handler/sign_psbt/musig_signing.c
@@ -7,6 +7,7 @@
/* Local headers */
#include "client_commands.h"
+#include "commands.h"
#include "get_merkleized_map_value.h"
#include "policy.h"
#include "psbt.h"
diff --git a/src/main.c b/src/main.c
index b00e16b..21b2e9c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -21,7 +21,9 @@
/* SDK headers */
#include "nbgl_use_case.h"
+#include "io.h"
#include "os.h"
+#include "swap.h"
#include "ux.h"
/* Local headers */
@@ -29,9 +31,6 @@
#include "constants.h"
#include "debug.h"
#include "dispatcher.h"
-#include "globals.h"
-#include "handle_check_address.h"
-#include "handle_get_printable_amount.h"
#include "handle_swap_sign_transaction.h"
#include "handlers.h"
#include "io_ext.h"
@@ -46,10 +45,6 @@
extern unsigned int app_stack_canary;
#endif
-uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
-ux_state_t G_ux;
-bolos_ux_params_t G_ux_params;
-
dispatcher_context_t G_dispatcher_context;
extern const char GA_SIGNING_TRANSACTION[];
@@ -89,22 +84,49 @@ const command_descriptor_t COMMAND_DESCRIPTORS[] = {
};
// clang-format on
+static void initialize_app_globals() {
+ io_reset_timeouts();
+
+ // We only zero out should_exit field and not the entire G_swap_state, as
+ // we need the globals initialization to happen _after_ calling copy_transaction_parameters when
+ // processing a SIGN_TRANSACTION request from the swap app (which initializes the other fields
+ // of G_swap_state).
+ G_swap_state.should_exit = false;
+}
+
+/**
+ * Handle APDU command received and send back APDU response using handlers.
+ */
void app_main() {
- for (;;) {
- // Length of APDU command received in G_io_apdu_buffer
- int input_len = 0;
- // Structured APDU command
- command_t cmd;
+ // Length of APDU command received in G_io_apdu_buffer
+ int input_len = 0;
+ // Structured APDU command
+ command_t cmd;
+
+ io_init();
+
+#ifdef HAVE_SWAP
+ // When called in swap context as a library, we don't want to show the menu
+ if (!G_called_from_swap) {
+#endif
+ ui_menu_main();
+#ifdef HAVE_SWAP
+ }
+#endif
+ // Reset dispatcher state
+ explicit_bzero(&G_dispatcher_context, sizeof(G_dispatcher_context));
+ memset(G_io_apdu_buffer, 0, sizeof(G_io_apdu_buffer)); // paranoia
+
+ for (;;) {
// Reset length of APDU response
G_output_len = 0;
- // Receive command bytes in G_io_apdu_buffer
-
- input_len = io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, 0);
+ initialize_app_globals();
- if (input_len < 0) {
- PRINTF("=> io_exchange error\n");
+ // Receive command bytes in G_io_apdu_buffer
+ if ((input_len = io_recv_command()) < 0) {
+ PRINTF("=> io_recv_command failure\n");
return;
}
@@ -114,21 +136,19 @@ void app_main() {
if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) {
PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer);
io_send_sw(SW_WRONG_DATA_LENGTH);
- return;
+ continue;
}
- PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=",
+ PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n",
cmd.cla,
cmd.ins,
cmd.p1,
cmd.p2,
- cmd.lc);
- for (int i = 0; i < cmd.lc; i++) {
- PRINTF("%02X", cmd.data[i]);
- }
- PRINTF("\n");
+ cmd.lc,
+ cmd.lc,
+ cmd.data);
- if (G_swap_state.called_from_swap) {
+ if (G_called_from_swap) {
if (cmd.cla != CLA_APP) {
io_send_sw(SW_CLA_NOT_SUPPORTED);
continue;
@@ -148,192 +168,9 @@ void app_main() {
sizeof(COMMAND_DESCRIPTORS) / sizeof(COMMAND_DESCRIPTORS[0]),
ui_menu_main,
&cmd);
-
- if (G_swap_state.called_from_swap && G_swap_state.should_exit) {
+ if (G_called_from_swap && G_swap_state.should_exit) {
// Bitcoin app will keep listening as long as it does not receive a valid TX
finalize_exchange_sign_transaction(true);
}
}
}
-
-/**
- * Exit the application and go back to the dashboard.
- */
-void app_exit() {
- BEGIN_TRY_L(exit) {
- TRY_L(exit) {
- os_sched_exit(-1);
- }
- FINALLY_L(exit) {
- }
- }
- END_TRY_L(exit);
-}
-
-static void initialize_app_globals() {
- io_reset_timeouts();
-
- // We only zero the called_from_swap and should_exit fields and not the entire G_swap_state, as
- // we need the globals initialization to happen _after_ calling copy_transaction_parameters when
- // processing a SIGN_TRANSACTION request from the swap app (which initializes the other fields
- // of G_swap_state).
- G_swap_state.called_from_swap = false;
- G_swap_state.should_exit = false;
-}
-
-/**
- * Handle APDU command received and send back APDU response using handlers.
- */
-void coin_main() {
- PRINT_STACK_POINTER();
-
- initialize_app_globals();
-
- // assumptions on the length of data structures
-
- _Static_assert(sizeof(cx_sha256_t) <= 108, "cx_sha256_t too large");
- _Static_assert(sizeof(policy_map_key_info_t) <= 156, "policy_map_key_info_t too large");
-
-#if defined(HAVE_PRINT_STACK_POINTER) && defined(HAVE_BOLOS_APP_STACK_CANARY)
- PRINTF("STACK CANARY ADDRESS: %08x\n", &app_stack_canary);
-#endif
-
- // Reset dispatcher state
- explicit_bzero(&G_dispatcher_context, sizeof(G_dispatcher_context));
-
- memset(G_io_apdu_buffer, 0, 255); // paranoia
-
- // Process the incoming APDUs
-
- for (;;) {
- UX_INIT();
- BEGIN_TRY {
- TRY {
- io_seproxyhal_init();
-
-#ifdef HAVE_BLE
- // grab the current plane mode setting
- G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
-#endif // HAVE_BLE
-
- USB_power(0);
- USB_power(1);
-
- ui_menu_main();
-
-#ifdef HAVE_BLE
- BLE_power(0, NULL);
- BLE_power(1, "Nano X");
-#endif // HAVE_BLE
-
- app_main();
- }
- CATCH(EXCEPTION_IO_RESET) {
- // reset IO and UX
- CLOSE_TRY;
- continue;
- }
- CATCH_ALL {
- CLOSE_TRY;
- break;
- }
- FINALLY {
- }
- }
- END_TRY;
- }
- app_exit();
-}
-
-static void swap_library_main_helper(libargs_t *args) {
- PRINTF("Inside a library \n");
- switch (args->command) {
- case CHECK_ADDRESS:
- // ensure result is zero if an exception is thrown
- args->check_address->result = 0;
- args->check_address->result = handle_check_address(args->check_address);
- break;
- case SIGN_TRANSACTION: {
- // copying arguments (pointing to globals) to context *before*
- // calling `initialize_app_globals` as it could override them
- const bool args_are_copied = copy_transaction_parameters(args->create_transaction);
- initialize_app_globals();
- if (args_are_copied) {
- // never returns
-
- G_swap_state.called_from_swap = 1;
-
- io_seproxyhal_init();
- UX_INIT();
- nbgl_useCaseSpinner(GA_SIGNING_TRANSACTION);
-
- USB_power(0);
- USB_power(1);
- // ui_idle();
- PRINTF("USB power ON/OFF\n");
-#ifdef HAVE_BLE
- // grab the current plane mode setting
- G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
- BLE_power(0, NULL);
- BLE_power(1, NULL);
-#endif // HAVE_BLE
- app_main();
- }
- break;
- }
- case GET_PRINTABLE_AMOUNT:
- // ensure result is zero if an exception is thrown (compatibility breaking, disabled
- // until LL is ready)
- // args->get_printable_amount->result = 0;
- // args->get_printable_amount->result =
- handle_get_printable_amount(args->get_printable_amount);
- break;
- default:
- break;
- }
-}
-
-void swap_library_main(libargs_t *args) {
- bool end = false;
- /* This loop ensures that swap_library_main_helper and os_lib_end are called
- * within a try context, even if an exception is thrown */
- while (1) {
- BEGIN_TRY {
- TRY {
- if (!end) {
- swap_library_main_helper(args);
- }
- os_lib_end();
- }
- FINALLY {
- end = true;
- }
- }
- END_TRY;
- }
-}
-
-__attribute__((section(".boot"))) int main(int arg0) {
- // exit critical section
- __asm volatile("cpsie i");
-
- // ensure exception will work as planned
- os_boot();
-
- if (!arg0) {
- // Application launched from dashboard
- coin_main();
- return 0;
- }
-
- // Application launched as library (for swap support)
- libargs_t *args = (libargs_t *) arg0;
- if (args->id != 0x100) {
- app_exit();
- return 0;
- }
-
- swap_library_main(args);
-
- return 0;
-}
diff --git a/src/swap/handle_check_address.c b/src/swap/handle_check_address.c
index 733c2ed..c3c472f 100644
--- a/src/swap/handle_check_address.c
+++ b/src/swap/handle_check_address.c
@@ -1,10 +1,9 @@
#include <string.h>
-#include "handle_check_address.h"
-
/* SDK headers */
#include "bip32_path.h"
#include "os.h"
+#include "swap_lib_calls.h"
/* Local headers */
#include "crypto.h"
@@ -95,26 +94,27 @@ static int os_strcmp(const char* s1, const char* s2) {
return memcmp(s1, s2, size);
}
-int handle_check_address(check_address_parameters_t* params) {
+void swap_handle_check_address(check_address_parameters_t* params) {
unsigned char compressed_public_key[33];
PRINTF("Params on the address %d\n", (unsigned int) params);
PRINTF("Address to check %s\n", params->address_to_check);
PRINTF("Inside handle_check_address\n");
+ params->result = 0;
if (params->address_to_check == 0) {
PRINTF("Address to check == 0\n");
- return 0;
+ return;
}
bip32_path_t path;
if (!parse_serialized_path(&path,
params->address_parameters + 1,
params->address_parameters_length - 1)) {
PRINTF("Can't parse path\n");
- return false;
+ return;
}
if (CX_OK !=
crypto_get_compressed_pubkey_at_path(path.path, path.length, compressed_public_key, NULL)) {
- return 0;
+ return;
}
char address[MAX_ADDRESS_LENGTH_STR + 1];
if (!get_address_from_compressed_public_key(params->address_parameters[0],
@@ -125,12 +125,12 @@ int handle_check_address(check_address_parameters_t* params) {
address,
sizeof(address))) {
PRINTF("Can't create address from given public key\n");
- return 0;
+ return;
}
if (os_strcmp(address, params->address_to_check) != 0) {
PRINTF("Addresses don't match\n");
- return 0;
+ return;
}
PRINTF("Addresses match\n");
- return 1;
+ params->result = 1;
}
diff --git a/src/swap/handle_check_address.h b/src/swap/handle_check_address.h
deleted file mode 100644
index f022b89..0000000
--- a/src/swap/handle_check_address.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-/* Local headers */
-#include "swap_lib_calls.h"
-
-int handle_check_address(check_address_parameters_t* check_address_params);
diff --git a/src/swap/handle_get_printable_amount.c b/src/swap/handle_get_printable_amount.c
index 75ca90b..2af6bc1 100644
--- a/src/swap/handle_get_printable_amount.c
+++ b/src/swap/handle_get_printable_amount.c
@@ -1,18 +1,17 @@
-#include "handle_get_printable_amount.h"
-
/* SDK headers */
#include "read.h"
+#include "swap_lib_calls.h"
/* Local headers */
#include "display_utils.h"
#define MAX_NON_PRINTABLE_AMOUNT_LEN 8
-int handle_get_printable_amount(get_printable_amount_parameters_t *params) {
+void swap_handle_get_printable_amount(get_printable_amount_parameters_t *params) {
params->printable_amount[0] = 0;
if (params->amount_length > MAX_NON_PRINTABLE_AMOUNT_LEN) {
PRINTF("Amount is too big");
- return 0;
+ return;
}
unsigned char amount[MAX_NON_PRINTABLE_AMOUNT_LEN] = {0};
/* Amount + ' ' + ticker */
@@ -23,5 +22,4 @@ int handle_get_printable_amount(get_printable_amount_parameters_t *params) {
format_sats_amount(COIN_COINID_SHORT,
(uint64_t) (read_u64_be(amount, 0)), // Cast prevents weird compilo bug
params->printable_amount);
- return 1;
}
diff --git a/src/swap/handle_get_printable_amount.h b/src/swap/handle_get_printable_amount.h
deleted file mode 100644
index a3619a1..0000000
--- a/src/swap/handle_get_printable_amount.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-/* Local headers */
-#include "swap_lib_calls.h"
-
-int handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params);
\ No newline at end of file
diff --git a/src/swap/handle_swap_sign_transaction.c b/src/swap/handle_swap_sign_transaction.c
index cf5e134..a8f0d9b 100644
--- a/src/swap/handle_swap_sign_transaction.c
+++ b/src/swap/handle_swap_sign_transaction.c
@@ -5,10 +5,10 @@
/* SDK headers */
#include "os.h"
#include "read.h"
+#include "swap_lib_calls.h"
#include "ux.h"
/* Local headers */
-#include "globals.h"
#include "os_io_seproxyhal.h"
#include "swap_globals.h"
#include "usbd_core.h"
@@ -16,7 +16,7 @@
// Save the BSS address where we will write the return value when finished
static uint8_t* G_swap_sign_return_value_address;
-bool copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params) {
+bool swap_copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params) {
char destination_address[65];
uint8_t destination_address_extra_data[33];
uint8_t amount[8];
diff --git a/src/swap/handle_swap_sign_transaction.h b/src/swap/handle_swap_sign_transaction.h
index 9516ab6..cecb0f9 100644
--- a/src/swap/handle_swap_sign_transaction.h
+++ b/src/swap/handle_swap_sign_transaction.h
@@ -1,8 +1,3 @@
#pragma once
-/* Local headers */
-#include "swap_lib_calls.h"
-
-bool copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params);
-
void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_success);
diff --git a/src/swap/swap_globals.h b/src/swap/swap_globals.h
index 7d8984f..a9f0b06 100644
--- a/src/swap/swap_globals.h
+++ b/src/swap/swap_globals.h
@@ -12,8 +12,6 @@ typedef struct swap_globals_s {
uint64_t amount;
uint64_t fees;
char destination_address[65];
- /*Is swap mode*/
- unsigned char called_from_swap;
unsigned char should_exit;
unsigned char mode;
uint8_t payin_extra_id[1 + 32];
diff --git a/src/ui/display.h b/src/ui/display.h
index c063af4..85d8163 100644
--- a/src/ui/display.h
+++ b/src/ui/display.h
@@ -11,7 +11,6 @@
#include "dispatcher.h"
#include "display.h"
#include "display_utils.h"
-#include "globals.h"
#include "io_ext.h"
#include "script.h"
#include "sw.h"
diff --git a/src/ui/menu_nbgl.c b/src/ui/menu_nbgl.c
index 7718a2e..2deed25 100644
--- a/src/ui/menu_nbgl.c
+++ b/src/ui/menu_nbgl.c
@@ -20,7 +20,6 @@
/* Local headers */
#include "display.h"
-#include "globals.h"
#include "menu.h"
#define SETTING_INFO_NB 3
Why this scored 32/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.