diff --git a/CHANGELOG.md b/CHANGELOG.md index f7b3867..c6ba0c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,29 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.9.20](https://github.com/ledgerhq/app-ethereum/compare/1.9.19...1.9.20) - 2022-XX-XX +## [1.10.0](https://github.com/ledgerhq/app-ethereum/compare/1.9.20...1.10.0) - 2022-XX-XX + +## [1.9.20](https://github.com/ledgerhq/app-ethereum/compare/1.9.19...1.9.20) - 2022-10-10 + +### Added + +- (clone) XDCNetwork +- (clone) Meter +- (clone) Multivac +- (clone) Tecra +- (clone) ApothemNetwork + +### Changed + +- EIP-191 improvements, now lets the user see the entire message one chunk at a time (255 characters for LNX & LNS+, 99 for LNS) + +### Fixed + +- Allow swap with variants + +### Removed + +- Compound support (will become its own plugin) ## [1.9.19](https://github.com/ledgerhq/app-ethereum/compare/1.9.18...1.9.19) - 2022-06-15 @@ -18,7 +40,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed -- EIP-191 signatures now show (up to 99 characters on LNS and 255 on LNX & LNS) the actual data contained in the message (clear-signing) +- EIP-191 signatures now show (up to 99 characters on LNS and 255 on LNX & LNS+) the actual data contained in the message (clear-signing) ### Fixed @@ -66,7 +88,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed -- Fixed stark order signature on LNS +- Fixed stark order signature on LNS ## [1.9.13](https://github.com/ledgerhq/app-ethereum/compare/1.9.12...1.9.13) - 2021-11-17 @@ -78,7 +100,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed -- Fixed stark order signature on LNX +- Fixed stark order signature on LNX ## [1.9.11](https://github.com/ledgerhq/app-ethereum/compare/1.9.10...1.9.11) - 2021-10-12 diff --git a/Makefile b/Makefile index 28b1a6d..f41e67a 100644 --- a/Makefile +++ b/Makefile @@ -33,10 +33,10 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'" ################## APPVERSION_M=1 -APPVERSION_N=9 -APPVERSION_P=20 +APPVERSION_N=10 +APPVERSION_P=0 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-dev -APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION) +APP_LOAD_FLAGS= --appFlags 0xa40 --dep Ethereum:$(APPVERSION) ########################### # Set Chain environnement # diff --git a/src/apdu_constants.h b/src/apdu_constants.h index 234294e..8cf18ce 100644 --- a/src/apdu_constants.h +++ b/src/apdu_constants.h @@ -65,6 +65,9 @@ enum { OFFSET_CLA = 0, OFFSET_INS, OFFSET_P1, OFFSET_P2, OFFSET_LC, OFFSET_CDATA }; +#define ERR_APDU_EMPTY 0x6982 +#define ERR_APDU_SIZE_MISMATCH 0x6983 + void handleGetPublicKey(uint8_t p1, uint8_t p2, const uint8_t *dataBuffer, @@ -95,12 +98,10 @@ void handleGetAppConfiguration(uint8_t p1, uint8_t dataLength, unsigned int *flags, unsigned int *tx); -void handleSignPersonalMessage(uint8_t p1, +bool handleSignPersonalMessage(uint8_t p1, uint8_t p2, - const uint8_t *dataBuffer, - uint8_t dataLength, - unsigned int *flags, - unsigned int *tx); + const uint8_t *const payload, + uint8_t length); void handleSignEIP712Message_v0(uint8_t p1, uint8_t p2, const uint8_t *dataBuffer, diff --git a/src/common_ui.h b/src/common_ui.h index 9b65600..3bca6b9 100644 --- a/src/common_ui.h +++ b/src/common_ui.h @@ -18,7 +18,14 @@ void ui_stark_limit_order(void); void ui_stark_unsafe_sign(void); void ui_stark_transfer(bool selfTransfer, bool conditional); +// EIP-191 +void ui_191_start(void); +void ui_191_switch_to_message(void); +void ui_191_switch_to_message_end(void); +void ui_191_switch_to_sign(void); +void ui_191_switch_to_question(void); + #include "ui_callbacks.h" #include -#endif // _COMMON_UI_H_ \ No newline at end of file +#endif // _COMMON_UI_H_ diff --git a/src/eth_plugin_handler.c b/src/eth_plugin_handler.c index e5187ca..22ffbe8 100644 --- a/src/eth_plugin_handler.c +++ b/src/eth_plugin_handler.c @@ -348,13 +348,13 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { } break; case ETH_PLUGIN_QUERY_CONTRACT_ID: - if (((ethQueryContractID_t *) parameter)->result <= ETH_PLUGIN_RESULT_UNSUCCESSFUL) { - return ETH_PLUGIN_RESULT_UNAVAILABLE; + if (((ethQueryContractID_t *) parameter)->result != ETH_PLUGIN_RESULT_OK) { + return ETH_PLUGIN_RESULT_ERROR; } break; case ETH_PLUGIN_QUERY_CONTRACT_UI: - if (((ethQueryContractUI_t *) parameter)->result <= ETH_PLUGIN_RESULT_UNSUCCESSFUL) { - return ETH_PLUGIN_RESULT_UNAVAILABLE; + if (((ethQueryContractUI_t *) parameter)->result != ETH_PLUGIN_RESULT_OK) { + return ETH_PLUGIN_RESULT_ERROR; } break; default: diff --git a/src/eth_plugin_internal.c b/src/eth_plugin_internal.c index 0e28ca6..b266969 100644 --- a/src/eth_plugin_internal.c +++ b/src/eth_plugin_internal.c @@ -4,7 +4,6 @@ bool erc20_plugin_available_check(void); void erc20_plugin_call(int message, void* parameters); -void compound_plugin_call(int message, void* parameters); void copy_address(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size) { uint8_t copy_size = MIN(dst_size, ADDRESS_LENGTH); @@ -29,17 +28,6 @@ static const uint8_t ERC20_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = {ERC20_TRANSFER_SELECTOR, ERC20_APPROVE_SELECTOR}; -static const uint8_t COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = {0x85, 0x2a, 0x12, 0xe3}; -static const uint8_t COMPOUND_REDEEM_SELECTOR[SELECTOR_SIZE] = {0xdb, 0x00, 0x6a, 0x75}; -static const uint8_t COMPOUND_MINT_SELECTOR[SELECTOR_SIZE] = {0xa0, 0x71, 0x2d, 0x68}; -static const uint8_t CETH_MINT_SELECTOR[SELECTOR_SIZE] = {0x12, 0x49, 0xc5, 0x8b}; - -const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = { - COMPOUND_REDEEM_UNDERLYING_SELECTOR, - COMPOUND_REDEEM_SELECTOR, - COMPOUND_MINT_SELECTOR, - CETH_MINT_SELECTOR}; - #ifdef HAVE_ETH2 static const uint8_t ETH2_DEPOSIT_SELECTOR[SELECTOR_SIZE] = {0x22, 0x89, 0x51, 0x18}; @@ -111,12 +99,6 @@ const internalEthPlugin_t INTERNAL_ETH_PLUGINS[] = { "-erc20", erc20_plugin_call}, - {NULL, - (const uint8_t**) COMPOUND_SELECTORS, - NUM_COMPOUND_SELECTORS, - "-cmpd", - compound_plugin_call}, - #ifdef HAVE_ETH2 {NULL, (const uint8_t**) ETH2_SELECTORS, NUM_ETH2_SELECTORS, "-eth2", eth2_plugin_call}, diff --git a/src/eth_plugin_internal.h b/src/eth_plugin_internal.h index 4d26130..1ad8382 100644 --- a/src/eth_plugin_internal.h +++ b/src/eth_plugin_internal.h @@ -29,9 +29,6 @@ typedef struct internalEthPlugin_t { #define NUM_ERC20_SELECTORS 2 extern const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS]; -#define NUM_COMPOUND_SELECTORS 4 -extern const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS]; - #ifdef HAVE_ETH2 #define NUM_ETH2_SELECTORS 1 diff --git a/src/main.c b/src/main.c index f3b37bc..cc67580 100644 --- a/src/main.c +++ b/src/main.c @@ -666,12 +666,11 @@ void handleApdu(unsigned int *flags, unsigned int *tx) { case INS_SIGN_PERSONAL_MESSAGE: memset(tmpCtx.transactionContext.tokenSet, 0, MAX_ITEMS); + *flags |= IO_ASYNCH_REPLY; handleSignPersonalMessage(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, - G_io_apdu_buffer[OFFSET_LC], - flags, - tx); + G_io_apdu_buffer[OFFSET_LC]); break; case INS_SIGN_EIP_712_MESSAGE: @@ -799,9 +798,11 @@ void app_main(void) { // no apdu received, well, reset the session, and reset the // bootloader configuration if (rx == 0) { - THROW(0x6982); + THROW(ERR_APDU_EMPTY); + } + if (rx > OFFSET_LC && rx != (G_io_apdu_buffer[OFFSET_LC] + 5)) { + THROW(ERR_APDU_SIZE_MISMATCH); } - PRINTF("New APDU received:\n%.*H\n", rx, G_io_apdu_buffer); handleApdu(&flags, &tx); } diff --git a/src/ui_callbacks.h b/src/ui_callbacks.h index a2512c4..2035c27 100644 --- a/src/ui_callbacks.h +++ b/src/ui_callbacks.h @@ -10,8 +10,8 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e); +unsigned int io_seproxyhal_touch_signMessage_ok(void); +unsigned int io_seproxyhal_touch_signMessage_cancel(void); unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_eth2_address_ok(const bagl_element_t *e); @@ -21,7 +21,6 @@ unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_stark_pubkey_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e); -void ui_idle(void); void ui_warning_contract_data(void); void io_seproxyhal_send_status(uint32_t sw); diff --git a/src_bagl/common_ui.c b/src_bagl/common_ui.c index 57be492..e1449f0 100644 --- a/src_bagl/common_ui.c +++ b/src_bagl/common_ui.c @@ -32,10 +32,6 @@ void ui_display_public_key(void) { ux_flow_init(0, ux_display_public_flow, NULL); } -void ui_display_sign(void) { - ux_flow_init(0, ux_sign_flow, NULL); -} - void ui_sign_712_v0(void) { ux_flow_init(0, ux_sign_712_v0_flow, NULL); } @@ -74,4 +70,4 @@ void ui_confirm_parameter(void) { ux_flow_init(0, ux_confirm_parameter_flow, NULL); } -#endif // HAVE_BAGL \ No newline at end of file +#endif // HAVE_BAGL diff --git a/src_bagl/ui_flow.c b/src_bagl/ui_flow.c index a1bc93a..cbb6f25 100644 --- a/src_bagl/ui_flow.c +++ b/src_bagl/ui_flow.c @@ -1,5 +1,5 @@ #include "shared_context.h" -#include "ui_callbacks.h" +#include "common_ui.h" void display_settings(const ux_flow_step_t* const start_step); void switch_settings_blind_signing(void); diff --git a/src_bagl/ui_flow.h b/src_bagl/ui_flow.h index 7b18286..184036b 100644 --- a/src_bagl/ui_flow.h +++ b/src_bagl/ui_flow.h @@ -20,8 +20,6 @@ extern const ux_flow_step_t* const ux_confirm_parameter_flow[]; extern const ux_flow_step_t* const ux_approval_allowance_flow[]; -extern const ux_flow_step_t* const ux_sign_flow[]; - extern const ux_flow_step_t* const ux_sign_712_v0_flow[]; extern const ux_flow_step_t* const ux_display_public_eth2_flow[]; diff --git a/src_bagl/ui_flow_signMessage.c b/src_bagl/ui_flow_signMessage.c index ee8e39e..9b97d57 100644 --- a/src_bagl/ui_flow_signMessage.c +++ b/src_bagl/ui_flow_signMessage.c @@ -1,9 +1,33 @@ #include "shared_context.h" #include "ui_callbacks.h" +#include "common_ui.h" +#include "sign_message.h" + +typedef enum { UI_191_POS_REVIEW, UI_191_POS_QUESTION, UI_191_POS_END } e_ui_191_position; + +static uint8_t ui_pos; + +static void dummy_pre_cb(void) { + if (ui_pos == UI_191_POS_REVIEW) { + question_switcher(); + } else { + ux_flow_prev(); + ui_pos = UI_191_POS_REVIEW; + } +} + +static void dummy_post_cb(void) { + if (ui_pos == UI_191_POS_QUESTION) { + continue_displaying_message(); + } else // UI_191_END + { + ui_191_switch_to_message_end(); + } +} // clang-format off UX_STEP_NOCB( - ux_sign_flow_1_step, + ux_191_step_review, pnn, { &C_icon_certificate, @@ -11,25 +35,56 @@ UX_STEP_NOCB( "message", }); UX_STEP_NOCB( - ux_sign_flow_2_step, + ux_191_step_message, bnnn_paging, { .title = "Message", .text = strings.tmp.tmp, }); +UX_STEP_INIT( + ux_191_step_dummy_pre, + NULL, + NULL, + { + dummy_pre_cb(); + }); UX_STEP_CB( - ux_sign_flow_3_step, + ux_191_step_theres_more, +#ifdef TARGET_NANOS + nn, +#else + nnn, +#endif + skip_rest_of_message(), + { +#ifndef TARGET_NANOS + "Press right to", + "continue message", +#else + "Press right to read", +#endif + "Double-press to skip" + }); +UX_STEP_INIT( + ux_191_step_dummy_post, + NULL, + NULL, + { + dummy_post_cb(); + }); +UX_STEP_CB( + ux_191_step_sign, pbb, - io_seproxyhal_touch_signMessage_ok(NULL), + io_seproxyhal_touch_signMessage_ok(), { &C_icon_validate_14, "Sign", "message", }); UX_STEP_CB( - ux_sign_flow_4_step, + ux_191_step_cancel, pbb, - io_seproxyhal_touch_signMessage_cancel(NULL), + io_seproxyhal_touch_signMessage_cancel(), { &C_icon_crossmark, "Cancel", @@ -37,8 +92,37 @@ UX_STEP_CB( }); // clang-format on -UX_FLOW(ux_sign_flow, - &ux_sign_flow_1_step, - &ux_sign_flow_2_step, - &ux_sign_flow_3_step, - &ux_sign_flow_4_step); +UX_FLOW(ux_191_flow, + &ux_191_step_review, + &ux_191_step_message, + &ux_191_step_dummy_pre, + &ux_191_step_theres_more, + &ux_191_step_dummy_post, + &ux_191_step_sign, + &ux_191_step_cancel); + +void ui_191_start(void) { + ux_flow_init(0, ux_191_flow, NULL); + ui_pos = UI_191_POS_REVIEW; +} + +void ui_191_switch_to_message(void) { + ux_flow_init(0, ux_191_flow, &ux_191_step_message); + ui_pos = UI_191_POS_REVIEW; +} + +void ui_191_switch_to_message_end(void) { + // Force it to a value that will make it automatically do a prev() + ui_pos = UI_191_POS_QUESTION; + ux_flow_init(0, ux_191_flow, &ux_191_step_dummy_pre); +} + +void ui_191_switch_to_sign(void) { + ux_flow_init(0, ux_191_flow, &ux_191_step_sign); + ui_pos = UI_191_POS_END; +} + +void ui_191_switch_to_question(void) { + ux_flow_init(0, ux_191_flow, &ux_191_step_theres_more); + ui_pos = UI_191_POS_QUESTION; +} diff --git a/src_bagl/ui_flow_signTx.c b/src_bagl/ui_flow_signTx.c index 6d05d6d..574dd9c 100644 --- a/src_bagl/ui_flow_signTx.c +++ b/src_bagl/ui_flow_signTx.c @@ -7,6 +7,7 @@ #include "eth_plugin_handler.h" #include "ui_plugin.h" #include "common_ui.h" +#include "plugins.h" // clang-format off UX_STEP_NOCB( diff --git a/src_bagl/ui_flow_stark_sign.c b/src_bagl/ui_flow_stark_sign.c index df3c6a1..548e880 100644 --- a/src_bagl/ui_flow_stark_sign.c +++ b/src_bagl/ui_flow_stark_sign.c @@ -3,18 +3,7 @@ #include "shared_context.h" #include "ui_callbacks.h" #include "ethUtils.h" - -void stark_sign_display_master_account() { - snprintf(strings.tmp.tmp, - sizeof(strings.tmp.tmp), - "0x%.*H", - 32, - dataContext.starkContext.transferDestination); -} - -void stark_sign_display_condition_fact() { - snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.fact); -} +#include "starkDisplayUtils.h" // clang-format off UX_STEP_NOCB(ux_stark_limit_order_1_step, diff --git a/src_bagl/ui_plugin.c b/src_bagl/ui_plugin.c index ed3f52f..c3743fa 100644 --- a/src_bagl/ui_plugin.c +++ b/src_bagl/ui_plugin.c @@ -3,38 +3,11 @@ #include "eth_plugin_handler.h" #include "ui_callbacks.h" #include "ui_plugin.h" +#include "plugins.h" // This function is not exported by the SDK void ux_layout_paging_redisplay_by_addr(unsigned int stack_slot); -void plugin_ui_get_id() { - ethQueryContractID_t pluginQueryContractID; - eth_plugin_prepare_query_contract_ID(&pluginQueryContractID, - strings.common.fullAddress, - sizeof(strings.common.fullAddress), - strings.common.fullAmount, - sizeof(strings.common.fullAmount)); - // Query the original contract for ID if it's not an internal alias - if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_ID, (void *) &pluginQueryContractID)) { - PRINTF("Plugin query contract ID call failed\n"); - io_seproxyhal_touch_tx_cancel(NULL); - } -} - -void plugin_ui_get_item() { - ethQueryContractUI_t pluginQueryContractUI; - eth_plugin_prepare_query_contract_UI(&pluginQueryContractUI, - dataContext.tokenContext.pluginUiCurrentItem, - strings.common.fullAddress, - sizeof(strings.common.fullAddress), - strings.common.fullAmount, - sizeof(strings.common.fullAmount)); - if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_UI, (void *) &pluginQueryContractUI)) { - PRINTF("Plugin query contract UI call failed\n"); - io_seproxyhal_touch_tx_cancel(NULL); - } -} - void display_next_plugin_item(bool entering) { if (entering) { if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) { diff --git a/src_bagl/ui_plugin.h b/src_bagl/ui_plugin.h index ae86b6a..2f9fe60 100644 --- a/src_bagl/ui_plugin.h +++ b/src_bagl/ui_plugin.h @@ -1,8 +1,6 @@ #ifndef _UI_PLUGIN_H_ #define _UI_PLUGIN_H_ -void plugin_ui_get_id(); -void plugin_ui_get_item(); void display_next_plugin_item(bool entering); #endif // _UI_PLUGIN_H_ diff --git a/src_common/network.h b/src_common/network.h index 8a4513a..ade3152 100644 --- a/src_common/network.h +++ b/src_common/network.h @@ -8,8 +8,8 @@ #define MAX_NETWORK_TICKER_LEN 8 typedef struct network_info_s { - const char name[NETWORK_STRING_MAX_SIZE]; - const char ticker[MAX_NETWORK_TICKER_LEN]; + const char *name; + const char *ticker; uint64_t chain_id; } network_info_t; diff --git a/src_common/plugins.c b/src_common/plugins.c new file mode 100644 index 0000000..42c17a9 --- /dev/null +++ b/src_common/plugins.c @@ -0,0 +1,40 @@ +#include "eth_plugin_handler.h" +#include "ui_callbacks.h" + +void plugin_ui_get_id(void) { + ethQueryContractID_t pluginQueryContractID; + eth_plugin_prepare_query_contract_ID(&pluginQueryContractID, + strings.common.fullAddress, + sizeof(strings.common.fullAddress), + strings.common.fullAmount, + sizeof(strings.common.fullAmount)); + // Query the original contract for ID if it's not an internal alias + if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_ID, (void *) &pluginQueryContractID)) { + PRINTF("Plugin query contract ID call failed\n"); + io_seproxyhal_touch_tx_cancel(NULL); + } +} + +void plugin_ui_get_item_internal(char *title_buffer, + size_t title_buffer_size, + char *msg_buffer, + size_t msg_buffer_size) { + ethQueryContractUI_t pluginQueryContractUI; + eth_plugin_prepare_query_contract_UI(&pluginQueryContractUI, + dataContext.tokenContext.pluginUiCurrentItem, + title_buffer, + title_buffer_size, + msg_buffer, + msg_buffer_size); + if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_UI, (void *) &pluginQueryContractUI)) { + PRINTF("Plugin query contract UI call failed\n"); + io_seproxyhal_touch_tx_cancel(NULL); + } +} + +void plugin_ui_get_item(void) { + plugin_ui_get_item_internal(strings.common.fullAddress, + sizeof(strings.common.fullAddress), + strings.common.fullAmount, + sizeof(strings.common.fullAmount)); +} \ No newline at end of file diff --git a/src_common/plugins.h b/src_common/plugins.h new file mode 100644 index 0000000..1ccc123 --- /dev/null +++ b/src_common/plugins.h @@ -0,0 +1,11 @@ +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +void plugin_ui_get_id(); +void plugin_ui_get_item(); +void plugin_ui_get_item_internal(uint8_t *title_buffer, + size_t title_buffer_size, + uint8_t *msg_buffer, + size_t msg_buffer_size); + +#endif // _PLUGIN_H_ \ No newline at end of file diff --git a/src_common/starkDisplayUtils.c b/src_common/starkDisplayUtils.c new file mode 100644 index 0000000..a59ae99 --- /dev/null +++ b/src_common/starkDisplayUtils.c @@ -0,0 +1,17 @@ +#ifdef HAVE_STARKWARE + +#include "shared_context.h" + +void stark_sign_display_master_account() { + snprintf(strings.tmp.tmp, + sizeof(strings.tmp.tmp), + "0x%.*H", + 32, + dataContext.starkContext.transferDestination); +} + +void stark_sign_display_condition_fact() { + snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.fact); +} + +#endif \ No newline at end of file diff --git a/src_common/starkDisplayUtils.h b/src_common/starkDisplayUtils.h new file mode 100644 index 0000000..48399b8 --- /dev/null +++ b/src_common/starkDisplayUtils.h @@ -0,0 +1,6 @@ +#ifdef HAVE_STARKWARE + +void stark_sign_display_master_account(); +void stark_sign_display_condition_fact(); + +#endif \ No newline at end of file diff --git a/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c b/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c index ca10fc3..77b38c0 100644 --- a/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c +++ b/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c @@ -2,7 +2,7 @@ #include "shared_context.h" #include "feature_getEth2PublicKey.h" -#include "ui_callbacks.h" +#include "common_ui.h" unsigned int io_seproxyhal_touch_eth2_address_ok(__attribute__((unused)) const bagl_element_t *e) { uint32_t tx = set_result_get_eth2_publicKey(); diff --git a/src_features/getPublicKey/ui_common_getPublicKey.c b/src_features/getPublicKey/ui_common_getPublicKey.c index c7bd3a3..d38724a 100644 --- a/src_features/getPublicKey/ui_common_getPublicKey.c +++ b/src_features/getPublicKey/ui_common_getPublicKey.c @@ -1,6 +1,6 @@ #include "shared_context.h" #include "feature_getPublicKey.h" -#include "ui_callbacks.h" +#include "common_ui.h" unsigned int io_seproxyhal_touch_address_ok(__attribute__((unused)) const bagl_element_t *e) { uint32_t tx = set_result_get_publicKey(); diff --git a/src_features/performPrivacyOperation/ui_common_performPrivacyOperation.c b/src_features/performPrivacyOperation/ui_common_performPrivacyOperation.c index ac045f2..a2cb1c3 100644 --- a/src_features/performPrivacyOperation/ui_common_performPrivacyOperation.c +++ b/src_features/performPrivacyOperation/ui_common_performPrivacyOperation.c @@ -1,6 +1,6 @@ #include "shared_context.h" #include "feature_getPublicKey.h" -#include "ui_callbacks.h" +#include "common_ui.h" #include "feature_performPrivacyOperation.h" unsigned int io_seproxyhal_touch_privacy_ok(__attribute__((unused)) const bagl_element_t *e) { diff --git a/src_features/signMessage/cmd_signMessage.c b/src_features/signMessage/cmd_signMessage.c index 68e17b5..1779142 100644 --- a/src_features/signMessage/cmd_signMessage.c +++ b/src_features/signMessage/cmd_signMessage.c @@ -1,199 +1,283 @@ #include -#include "shared_context.h" +#include +#include #include "apdu_constants.h" -#include "utils.h" +#include "sign_message.h" #include "common_ui.h" +static uint8_t processed_size; +static struct { + sign_message_state sign_state : 1; + bool ui_started : 1; +} states; + static const char SIGN_MAGIC[] = "\x19" "Ethereum Signed Message:\n"; /** - * Check if a given character is a "special" displayable ASCII character + * Send a response APDU with the given Status Word * - * @param[in] c character we're checking - * @return whether the character is special or not + * @param[in] sw status word */ -static inline bool is_char_special(char c) { - return ((c >= '\b') && (c <= '\r')); +static void apdu_reply(uint16_t sw) { + G_io_apdu_buffer[0] = (sw >> 8) & 0xff; + G_io_apdu_buffer[1] = sw & 0xff; + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); } /** - * Check if a given data is made of ASCII characters + * Get unprocessed data from last received APDU * - * @param[in] data the input data - * @param[in] the length of the input data - * @return whether the data is fully ASCII or not + * @return pointer to data in APDU buffer */ -static bool is_data_ascii(const uint8_t *const data, size_t length) { - for (uint8_t idx = 0; idx < length; ++idx) { - if (!is_char_special(data[idx]) && ((data[idx] < 0x20) || (data[idx] > 0x7e))) { +static const uint8_t *unprocessed_data(void) { + return &G_io_apdu_buffer[OFFSET_CDATA] + processed_size; +} + +/** + * Get size of unprocessed data from last received APDU + * + * @return size of data in bytes + */ +static size_t unprocessed_length(void) { + return G_io_apdu_buffer[OFFSET_LC] - processed_size; +} + +/** + * Get used space from UI buffer + * + * @return size in bytes + */ +static size_t ui_buffer_length(void) { + return strlen(UI_191_BUFFER); +} + +/** + * Get remaining space from UI buffer + * + * @return size in bytes + */ +static size_t remaining_ui_buffer_length(void) { + // -1 for the ending NULL byte + return (sizeof(UI_191_BUFFER) - 1) - ui_buffer_length(); +} + +/** + * Get free space from UI buffer + * + * @return pointer to the free space + */ +static char *remaining_ui_buffer(void) { + return &UI_191_BUFFER[ui_buffer_length()]; +} + +/** + * Reset the UI buffer + * + * Simply sets its first byte to a NULL character + */ +static void reset_ui_buffer(void) { + UI_191_BUFFER[0] = '\0'; +} + +/** + * Handle the data specific to the first APDU of an EIP-191 signature + * + * @param[in] data the APDU payload + * @param[in] length the payload size + * @return pointer to the start of the start of the message; \ref NULL if it failed + */ +static const uint8_t *first_apdu_data(const uint8_t *data, uint8_t *length) { + if (appState != APP_STATE_IDLE) { + reset_app_context(); + } + appState = APP_STATE_SIGNING_MESSAGE; + data = parseBip32(data, length, &tmpCtx.messageSigningContext.bip32); + if (data == NULL) { + apdu_reply(0x6a80); + return NULL; + } + + if (*length < sizeof(uint32_t)) { + PRINTF("Invalid data\n"); + apdu_reply(0x6a80); + return NULL; + } + + tmpCtx.messageSigningContext.remainingLength = U4BE(data, 0); + data += sizeof(uint32_t); + *length -= sizeof(uint32_t); + + // Initialize message header + length + cx_keccak_init(&global_sha3, 256); + cx_hash((cx_hash_t *) &global_sha3, 0, (uint8_t *) SIGN_MAGIC, sizeof(SIGN_MAGIC) - 1, NULL, 0); + snprintf(strings.tmp.tmp2, + sizeof(strings.tmp.tmp2), + "%u", + tmpCtx.messageSigningContext.remainingLength); + cx_hash((cx_hash_t *) &global_sha3, + 0, + (uint8_t *) strings.tmp.tmp2, + strlen(strings.tmp.tmp2), + NULL, + 0); + reset_ui_buffer(); + states.sign_state = STATE_191_HASH_DISPLAY; + states.ui_started = false; + return data; +} + +/** + * Feed the progressive hash with new data + * + * @param[in] data the new data + * @param[in] length the data length + * @return whether it was successful or not + */ +static bool feed_hash(const uint8_t *const data, const uint8_t length) { + if (length > tmpCtx.messageSigningContext.remainingLength) { + PRINTF("Error: Length mismatch ! (%u > %u)!\n", + length, + tmpCtx.messageSigningContext.remainingLength); + apdu_reply(0x6a80); + return false; + } + cx_hash((cx_hash_t *) &global_sha3, 0, data, length, NULL, 0); + if ((tmpCtx.messageSigningContext.remainingLength -= length) == 0) { + // Finalize hash + cx_hash((cx_hash_t *) &global_sha3, + CX_LAST, + NULL, + 0, + tmpCtx.messageSigningContext.hash, + 32); + } + return true; +} + +/** + * Feed the UI with new data + */ +static void feed_display(void) { + int c; + + while ((unprocessed_length() > 0) && (remaining_ui_buffer_length() > 0)) { + c = *(char *) unprocessed_data(); + if (isspace(c)) // to replace all white-space characters as spaces + { + c = ' '; + } + if (isprint(c)) { + sprintf(remaining_ui_buffer(), "%c", (char) c); + processed_size += 1; + } else { + if (remaining_ui_buffer_length() >= 4) // 4 being the fixed length of \x00 + { + snprintf(remaining_ui_buffer(), remaining_ui_buffer_length(), "\\x%02x", c); + processed_size += 1; + } else { + // fill the rest of the UI buffer spaces, to consider the buffer full + memset(remaining_ui_buffer(), ' ', remaining_ui_buffer_length()); + } + } + } + + if ((remaining_ui_buffer_length() == 0) || + (tmpCtx.messageSigningContext.remainingLength == 0)) { + if (!states.ui_started) { + ui_191_start(); + states.ui_started = true; + } else { + ui_191_switch_to_message(); + } + } + + if ((unprocessed_length() == 0) && (tmpCtx.messageSigningContext.remainingLength > 0)) { + apdu_reply(0x9000); + } +} + +/** + * EIP-191 APDU handler + * + * @param[in] p1 instruction parameter 1 + * @param[in] p2 instruction parameter 2 + * @param[in] payload received data + * @param[in] length data length + * @return whether the handling of the APDU was successful or not + */ +bool handleSignPersonalMessage(uint8_t p1, + uint8_t p2, + const uint8_t *const payload, + uint8_t length) { + const uint8_t *data = payload; + + (void) p2; + processed_size = 0; + if (p1 == P1_FIRST) { + if ((data = first_apdu_data(data, &length)) == NULL) { return false; } + processed_size = data - payload; + } else if (p1 != P1_MORE) { + PRINTF("Error: Unexpected P1 (%u)!\n", p1); + apdu_reply(0x6B00); + return false; + } + + if (!feed_hash(data, length)) { + return false; + } + + if (states.sign_state == STATE_191_HASH_DISPLAY) { + feed_display(); + } else // hash only + { + if (tmpCtx.messageSigningContext.remainingLength == 0) { +#ifdef NO_CONSENT + io_seproxyhal_touch_signMessage_ok(); +#else + ui_191_switch_to_sign(); +#endif + } else { + apdu_reply(0x9000); + } } return true; } /** - * Initialize value string that will be displayed in the UX STEP - * - * @param[in] if the value is ASCII + * Decide whether to show the question to show more of the message or not */ -static void init_value_str(bool is_ascii) { - if (is_ascii) { - strings.tmp.tmp[0] = '\0'; // init string as empty +void question_switcher(void) { + if ((states.sign_state == STATE_191_HASH_DISPLAY) && + ((tmpCtx.messageSigningContext.remainingLength > 0) || (unprocessed_length() > 0))) { + ui_191_switch_to_question(); } else { - strcpy(strings.tmp.tmp, "0x"); // will display the hex bytes instead + // Go to Sign / Cancel + ui_191_switch_to_sign(); } } /** - * @return Whether the currently stored data is initialized as ASCII or not + * The user has decided to skip the rest of the message */ -static bool is_value_str_ascii() { - return (memcmp(strings.tmp.tmp, "0x", 2) != 0); +void skip_rest_of_message(void) { + states.sign_state = STATE_191_HASH_ONLY; + if (tmpCtx.messageSigningContext.remainingLength > 0) { + apdu_reply(0x9000); + } else { + ui_191_switch_to_sign(); + } } /** - * Update the global UI string variable by formatting & appending the new data to it - * - * @param[in] data the input data - * @param[in] length the data length - * @param[in] is_ascii whether the data is ASCII or not + * The user has decided to see the next chunk of the message */ -static void feed_value_str(const uint8_t *const data, size_t length, bool is_ascii) { - uint16_t value_strlen = strlen(strings.tmp.tmp); - - if ((value_strlen + 1) < sizeof(strings.tmp.tmp)) { - if (is_ascii) { - uint8_t src_idx = 0; - uint16_t dst_idx = value_strlen; - bool prev_is_special = false; - - while ((src_idx < length) && (dst_idx < sizeof(strings.tmp.tmp))) { - if (prev_is_special) { - if (!is_char_special(data[src_idx])) { - prev_is_special = false; - } - } else { - if (is_char_special(data[src_idx])) { - prev_is_special = true; - strings.tmp.tmp[dst_idx] = ' '; - dst_idx += 1; - } - } - if (!is_char_special(data[src_idx])) { - strings.tmp.tmp[dst_idx] = data[src_idx]; - dst_idx += 1; - } - src_idx += 1; - } - - if (dst_idx < sizeof(strings.tmp.tmp)) { - strings.tmp.tmp[dst_idx] = '\0'; - } else { - const char marker[] = "..."; - - memcpy(strings.tmp.tmp + sizeof(strings.tmp.tmp) - sizeof(marker), - marker, - sizeof(marker)); - } - } else { - // truncate to strings.tmp.tmp 's size - length = MIN(length, (sizeof(strings.tmp.tmp) - value_strlen) / 2); - for (size_t i = 0; i < length; i++) { - snprintf(strings.tmp.tmp + value_strlen + 2 * i, - sizeof(strings.tmp.tmp) - value_strlen - 2 * i, - "%02X", - data[i]); - } - } - } -} - -void handleSignPersonalMessage(uint8_t p1, - uint8_t p2, - const uint8_t *workBuffer, - uint8_t dataLength, - unsigned int *flags, - unsigned int *tx) { - UNUSED(tx); - uint8_t hashMessage[INT256_LENGTH]; - - if (p1 == P1_FIRST) { - char tmp[11] = {0}; - - if (appState != APP_STATE_IDLE) { - reset_app_context(); - } - appState = APP_STATE_SIGNING_MESSAGE; - - workBuffer = parseBip32(workBuffer, &dataLength, &tmpCtx.messageSigningContext.bip32); - - if (workBuffer == NULL) { - THROW(0x6a80); - } - - if (dataLength < sizeof(uint32_t)) { - PRINTF("Invalid data\n"); - THROW(0x6a80); - } - - tmpCtx.messageSigningContext.remainingLength = U4BE(workBuffer, 0); - workBuffer += sizeof(uint32_t); - dataLength -= sizeof(uint32_t); - // Initialize message header + length - cx_keccak_init(&global_sha3, 256); - cx_hash((cx_hash_t *) &global_sha3, - 0, - (uint8_t *) SIGN_MAGIC, - sizeof(SIGN_MAGIC) - 1, - NULL, - 0); - snprintf(tmp, sizeof(tmp), "%u", tmpCtx.messageSigningContext.remainingLength); - cx_hash((cx_hash_t *) &global_sha3, 0, (uint8_t *) tmp, strlen(tmp), NULL, 0); - cx_sha256_init(&tmpContent.sha2); - - init_value_str(is_data_ascii(workBuffer, dataLength)); - - } else if (p1 != P1_MORE) { - THROW(0x6B00); - } - if (p2 != 0) { - THROW(0x6B00); - } - if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_MESSAGE)) { - PRINTF("Signature not initialized\n"); - THROW(0x6985); - } - if (dataLength > tmpCtx.messageSigningContext.remainingLength) { - THROW(0x6A80); - } - - cx_hash((cx_hash_t *) &global_sha3, 0, workBuffer, dataLength, NULL, 0); - cx_hash((cx_hash_t *) &tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0); - tmpCtx.messageSigningContext.remainingLength -= dataLength; - - feed_value_str(workBuffer, dataLength, is_value_str_ascii()); - - if (tmpCtx.messageSigningContext.remainingLength == 0) { - cx_hash((cx_hash_t *) &global_sha3, - CX_LAST, - workBuffer, - 0, - tmpCtx.messageSigningContext.hash, - 32); - cx_hash((cx_hash_t *) &tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32); - -#ifdef NO_CONSENT - io_seproxyhal_touch_signMessage_ok(NULL); -#else // NO_CONSENT - ui_display_sign(); -#endif // NO_CONSENT - - *flags |= IO_ASYNCH_REPLY; - - } else { - THROW(0x9000); +void continue_displaying_message(void) { + reset_ui_buffer(); + if (unprocessed_length() > 0) { + feed_display(); } } diff --git a/src_features/signMessage/sign_message.h b/src_features/signMessage/sign_message.h new file mode 100644 index 0000000..6d35e49 --- /dev/null +++ b/src_features/signMessage/sign_message.h @@ -0,0 +1,12 @@ +#ifndef SIGN_MESSAGE_H_ +#define SIGN_MESSAGE_H_ + +#define UI_191_BUFFER strings.tmp.tmp + +typedef enum { STATE_191_HASH_DISPLAY = 0, STATE_191_HASH_ONLY } sign_message_state; + +void question_switcher(void); +void skip_rest_of_message(void); +void continue_displaying_message(void); + +#endif // SIGN_MESSAGE_H_ diff --git a/src_features/signMessage/ui_common_signMessage.c b/src_features/signMessage/ui_common_signMessage.c index b8fc9c3..eb6707d 100644 --- a/src_features/signMessage/ui_common_signMessage.c +++ b/src_features/signMessage/ui_common_signMessage.c @@ -1,8 +1,7 @@ #include "os_io_seproxyhal.h" -#include "shared_context.h" -#include "ui_callbacks.h" +#include "common_ui.h" -unsigned int io_seproxyhal_touch_signMessage_ok(__attribute__((unused)) const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_signMessage_ok(void) { uint8_t privateKeyData[INT256_LENGTH]; uint8_t signature[100]; cx_ecfp_private_key_t privateKey; @@ -46,8 +45,7 @@ unsigned int io_seproxyhal_touch_signMessage_ok(__attribute__((unused)) const ba return 0; // do not redraw the widget } -unsigned int io_seproxyhal_touch_signMessage_cancel(__attribute__((unused)) - const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_signMessage_cancel(void) { reset_app_context(); G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[1] = 0x85; diff --git a/src_features/signMessageEIP712/context_712.c b/src_features/signMessageEIP712/context_712.c index 829398c..82abd09 100644 --- a/src_features/signMessageEIP712/context_712.c +++ b/src_features/signMessageEIP712/context_712.c @@ -12,7 +12,7 @@ #include "typed_data.h" #include "apdu_constants.h" // APDU response codes #include "shared_context.h" // reset_app_context -#include "ui_callbacks.h" // ui_idle +#include "common_ui.h" // ui_idle e_struct_init struct_state = NOT_INITIALIZED; s_eip712_context *eip712_context = NULL; diff --git a/src_features/signMessageEIP712_common/common_712.c b/src_features/signMessageEIP712_common/common_712.c index 4bed719..abc1fd5 100644 --- a/src_features/signMessageEIP712_common/common_712.c +++ b/src_features/signMessageEIP712_common/common_712.c @@ -2,6 +2,8 @@ #include "os_io_seproxyhal.h" #include "ui_callbacks.h" #include "common_712.h" +#include "ui_callbacks.h" +#include "common_ui.h" static const uint8_t EIP_712_MAGIC[] = {0x19, 0x01}; diff --git a/src_features/signTx/ui_common_signTx.c b/src_features/signTx/ui_common_signTx.c index 6c482d0..ef8171f 100644 --- a/src_features/signTx/ui_common_signTx.c +++ b/src_features/signTx/ui_common_signTx.c @@ -1,7 +1,7 @@ #include "os_io_seproxyhal.h" #include "shared_context.h" #include "utils.h" -#include "ui_callbacks.h" +#include "common_ui.h" unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_element_t *e) { uint8_t privateKeyData[INT256_LENGTH]; diff --git a/src_features/stark_getPublicKey/ui_common_stark_getPublicKey.c b/src_features/stark_getPublicKey/ui_common_stark_getPublicKey.c index 94a6658..31b9714 100644 --- a/src_features/stark_getPublicKey/ui_common_stark_getPublicKey.c +++ b/src_features/stark_getPublicKey/ui_common_stark_getPublicKey.c @@ -1,7 +1,7 @@ #ifdef HAVE_STARKWARE #include "shared_context.h" -#include "ui_callbacks.h" +#include "common_ui.h" #include "feature_stark_getPublicKey.h" unsigned int io_seproxyhal_touch_stark_pubkey_ok(__attribute__((unused)) const bagl_element_t *e) { diff --git a/src_features/stark_sign/ui_common_stark_sign.c b/src_features/stark_sign/ui_common_stark_sign.c index a44ee99..a45f7f9 100644 --- a/src_features/stark_sign/ui_common_stark_sign.c +++ b/src_features/stark_sign/ui_common_stark_sign.c @@ -3,7 +3,7 @@ #include "os_io_seproxyhal.h" #include "shared_context.h" #include "stark_utils.h" -#include "ui_callbacks.h" +#include "common_ui.h" unsigned int io_seproxyhal_touch_stark_ok(__attribute__((unused)) const bagl_element_t *e) { uint8_t privateKeyData[32]; diff --git a/src_features/stark_unsafe_sign/ui_common_stark_unsafe_sign.c b/src_features/stark_unsafe_sign/ui_common_stark_unsafe_sign.c index 899c59d..4774627 100644 --- a/src_features/stark_unsafe_sign/ui_common_stark_unsafe_sign.c +++ b/src_features/stark_unsafe_sign/ui_common_stark_unsafe_sign.c @@ -3,7 +3,7 @@ #include "os_io_seproxyhal.h" #include "shared_context.h" #include "stark_utils.h" -#include "ui_callbacks.h" +#include "common_ui.h" unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(__attribute__((unused)) const bagl_element_t *e) { diff --git a/src_plugins/compound/compound_plugin.c b/src_plugins/compound/compound_plugin.c deleted file mode 100644 index cbb68dd..0000000 --- a/src_plugins/compound/compound_plugin.c +++ /dev/null @@ -1,243 +0,0 @@ -#include -#include "eth_plugin_interface.h" -#include "shared_context.h" // TODO : rewrite as independant code -#include "eth_plugin_internal.h" // TODO : rewrite as independant code -#include "utils.h" -#include "ethUtils.h" - -typedef enum { - COMPOUND_REDEEM_UNDERLYING = 0, - COMPOUND_REDEEM, - COMPOUND_MINT, - CETH_MINT -} compoundSelector_t; - -static const uint8_t COMPOUND_EXPECTED_DATA_SIZE[] = { - 4 + 32, - 4 + 32, - 4 + 32, - 4, -}; - -// redeemUnderlying : redeemAmount (32) -// redeem underlying token -// redeem : redeemTokens (32) -// redeem Ctoken -// mint : mintAmount (32) -// lend some token -// mint : -// lend some Ether - -typedef struct compound_parameters_t { - uint8_t selectorIndex; - uint8_t amount[32]; - char ticker_1[MAX_TICKER_LEN]; - uint8_t decimals; -} compound_parameters_t; - -typedef struct underlying_asset_decimals_t { - char c_ticker[MAX_TICKER_LEN]; - uint8_t decimals; -} underlying_asset_decimals_t; - -/* Sadly, we don't have the information about the underlying asset's decimals, which can differ from -the cToken decimals. Therefore, we hardcode a binding table. If Compound adds a lot of token in the -future, we will have to move to a CAL based architecture instead, as this one doesn't scale well.*/ -#define NUM_COMPOUND_BINDINGS 9 -const underlying_asset_decimals_t UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_BINDINGS] = { - {"cDAI", 18}, - {"CETH", 18}, - {"CUSDC", 6}, - {"CZRX", 18}, - {"CUSDT", 6}, - {"CBTC", 8}, - {"CBAT", 18}, - {"CREP", 18}, - {"cSAI", 18}, -}; - -bool get_underlying_asset_decimals(char *compound_ticker, uint8_t *out_decimals) { - for (size_t i = 0; i < NUM_COMPOUND_BINDINGS; i++) { - underlying_asset_decimals_t *binding = - (underlying_asset_decimals_t *) PIC(&UNDERLYING_ASSET_DECIMALS[i]); - if (strncmp(binding->c_ticker, - compound_ticker, - strnlen(binding->c_ticker, MAX_TICKER_LEN)) == 0) { - *out_decimals = binding->decimals; - return true; - } - } - return false; -} - -void compound_plugin_call(int message, void *parameters) { - switch (message) { - case ETH_PLUGIN_INIT_CONTRACT: { - ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters; - compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext; - size_t i; - for (i = 0; i < NUM_COMPOUND_SELECTORS; i++) { - if (memcmp((uint8_t *) PIC(COMPOUND_SELECTORS[i]), msg->selector, SELECTOR_SIZE) == - 0) { - context->selectorIndex = i; - break; - } - } - // enforce that ETH amount should be 0, except in ceth.mint case - if (!allzeroes(msg->pluginSharedRO->txContent->value.value, 32)) { - if (context->selectorIndex != CETH_MINT) { - PRINTF("Eth amount is not zero and token minted is not CETH!\n"); - msg->result = ETH_PLUGIN_RESULT_ERROR; - break; - } - } - if (i == NUM_COMPOUND_SELECTORS) { - PRINTF("Unknown selector %.*H\n", SELECTOR_SIZE, msg->selector); - msg->result = ETH_PLUGIN_RESULT_ERROR; - break; - } - if (msg->dataSize != COMPOUND_EXPECTED_DATA_SIZE[context->selectorIndex]) { - PRINTF("Unexpected data size for command %d expected %d got %d\n", - context->selectorIndex, - COMPOUND_EXPECTED_DATA_SIZE[context->selectorIndex], - msg->dataSize); - msg->result = ETH_PLUGIN_RESULT_ERROR; - break; - } - if (context->selectorIndex == CETH_MINT) { - // ETH amount 0x1234 is stored 0x12340000...000 instead of 0x00....001234, so we - // strip the following zeroes when copying - memset(context->amount, 0, sizeof(context->amount)); - memmove(context->amount + sizeof(context->amount) - - msg->pluginSharedRO->txContent->value.length, - msg->pluginSharedRO->txContent->value.value, - msg->pluginSharedRO->txContent->value.length); - } - PRINTF("compound plugin inititialized\n"); - msg->result = ETH_PLUGIN_RESULT_OK; - } break; - - case ETH_PLUGIN_PROVIDE_PARAMETER: { - ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters; - compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext; - PRINTF("compound plugin provide parameter %d %.*H\n", - msg->parameterOffset, - 32, - msg->parameter); - if (context->selectorIndex != CETH_MINT) { - switch (msg->parameterOffset) { - case 4: - memmove(context->amount, msg->parameter, 32); - msg->result = ETH_PLUGIN_RESULT_OK; - break; - default: - PRINTF("Unhandled parameter offset\n"); - msg->result = ETH_PLUGIN_RESULT_ERROR; - break; - } - } else { - PRINTF("CETH contract expects no parameters\n"); - msg->result = ETH_PLUGIN_RESULT_ERROR; - } - } break; - - case ETH_PLUGIN_FINALIZE: { - ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters; - PRINTF("compound plugin finalize\n"); - msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination; - msg->numScreens = 2; - msg->uiType = ETH_UI_TYPE_GENERIC; - msg->result = ETH_PLUGIN_RESULT_OK; - } break; - - case ETH_PLUGIN_PROVIDE_INFO: { - ethPluginProvideInfo_t *msg = (ethPluginProvideInfo_t *) parameters; - compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext; - PRINTF("compound plugin provide token: %d\n", (msg->item1 != NULL)); - if (msg->item1 != NULL) { - strlcpy(context->ticker_1, msg->item1->token.ticker, MAX_TICKER_LEN); - switch (context->selectorIndex) { - case COMPOUND_REDEEM_UNDERLYING: - case COMPOUND_MINT: - case CETH_MINT: - msg->result = - get_underlying_asset_decimals(context->ticker_1, &context->decimals) - ? ETH_PLUGIN_RESULT_OK - : ETH_PLUGIN_RESULT_FALLBACK; - break; - - // Only case where we use the compound contract decimals - case COMPOUND_REDEEM: - context->decimals = msg->item1->token.decimals; - msg->result = ETH_PLUGIN_RESULT_OK; - break; - - default: - msg->result = ETH_PLUGIN_RESULT_FALLBACK; - break; - } - } else { - msg->result = ETH_PLUGIN_RESULT_FALLBACK; - } - } break; - - case ETH_PLUGIN_QUERY_CONTRACT_ID: { - ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters; - compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext; - strlcpy(msg->name, "Type", msg->nameLength); - switch (context->selectorIndex) { - case COMPOUND_REDEEM_UNDERLYING: - case COMPOUND_REDEEM: - strlcpy(msg->version, "Redeem", msg->versionLength); - break; - - case COMPOUND_MINT: - case CETH_MINT: - strlcpy(msg->version, "Lend", msg->versionLength); - break; - - default: - break; - } - strlcat(msg->version, " Assets", msg->versionLength); - msg->result = ETH_PLUGIN_RESULT_OK; - } break; - - case ETH_PLUGIN_QUERY_CONTRACT_UI: { - ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters; - compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext; - switch (msg->screenIndex) { - case 0: { - strlcpy(msg->title, "Amount", msg->titleLength); - char *ticker_ptr = context->ticker_1; - /* skip "c" in front of cToken unless we use "redeem", as - redeem is the only operation dealing with a cToken amount */ - if (context->selectorIndex != COMPOUND_REDEEM) { - ticker_ptr++; - } - amountToString(context->amount, - sizeof(context->amount), - context->decimals, - ticker_ptr, - msg->msg, - 100); - msg->result = ETH_PLUGIN_RESULT_OK; - } break; - - case 1: - strlcpy(msg->title, "Contract", msg->titleLength); - strlcpy(msg->msg, "Compound ", msg->msgLength); - strlcat(msg->msg, - context->ticker_1 + 1, - msg->msgLength); // remove the 'c' char at beginning of compound ticker - msg->result = ETH_PLUGIN_RESULT_OK; - break; - default: - break; - } - } break; - - default: - PRINTF("Unhandled message %d\n", message); - } -} diff --git a/tests/speculos/test_eip191.py b/tests/speculos/old_test_eip191.py similarity index 100% rename from tests/speculos/test_eip191.py rename to tests/speculos/old_test_eip191.py diff --git a/tests/speculos/test_configuration_cmd.py b/tests/speculos/test_configuration_cmd.py index 6f9e5e0..de41bde 100644 --- a/tests/speculos/test_configuration_cmd.py +++ b/tests/speculos/test_configuration_cmd.py @@ -1,10 +1,10 @@ def test_configuration(cmd): if cmd.model == "nanos": - assert cmd.get_configuration() == (14, 1, 9, 20) - + assert cmd.get_configuration() == (14, 1, 10, 0) + if cmd.model == "nanox": - assert cmd.get_configuration() == (14, 1, 9, 20) + assert cmd.get_configuration() == (14, 1, 10, 0) if cmd.model == "nanosp": - assert cmd.get_configuration() == (14, 1, 9, 20) \ No newline at end of file + assert cmd.get_configuration() == (14, 1, 10, 0) diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00001.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00001.png index ad00cb8..51efae0 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_nonascii/00001.png and b/tests/zemu/snapshots/nanos_eip191_nonascii/00001.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00002.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00002.png index b435297..b4e4df5 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_nonascii/00002.png and b/tests/zemu/snapshots/nanos_eip191_nonascii/00002.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00003.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00003.png index fcd68b2..d95e831 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_nonascii/00003.png and b/tests/zemu/snapshots/nanos_eip191_nonascii/00003.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00004.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00004.png index 251c562..e8c4c8e 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_nonascii/00004.png and b/tests/zemu/snapshots/nanos_eip191_nonascii/00004.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00005.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00005.png index f5c2d67..a259c69 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_nonascii/00005.png and b/tests/zemu/snapshots/nanos_eip191_nonascii/00005.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00006.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00006.png index d55782f..4ce22f6 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_nonascii/00006.png and b/tests/zemu/snapshots/nanos_eip191_nonascii/00006.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00008.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00008.png index ce795f3..d55782f 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_nonascii/00008.png and b/tests/zemu/snapshots/nanos_eip191_nonascii/00008.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00009.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00009.png new file mode 100644 index 0000000..f5c2d67 Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_nonascii/00009.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_nonascii/00010.png b/tests/zemu/snapshots/nanos_eip191_nonascii/00010.png new file mode 100644 index 0000000..ce795f3 Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_nonascii/00010.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00002.png b/tests/zemu/snapshots/nanos_eip191_opensea/00002.png index 0676953..1fd8170 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_opensea/00002.png and b/tests/zemu/snapshots/nanos_eip191_opensea/00002.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00005.png b/tests/zemu/snapshots/nanos_eip191_opensea/00005.png index 228f924..b1bddfe 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_opensea/00005.png and b/tests/zemu/snapshots/nanos_eip191_opensea/00005.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00006.png b/tests/zemu/snapshots/nanos_eip191_opensea/00006.png index f5c2d67..f872acc 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_opensea/00006.png and b/tests/zemu/snapshots/nanos_eip191_opensea/00006.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00007.png b/tests/zemu/snapshots/nanos_eip191_opensea/00007.png index d55782f..56b7f7b 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_opensea/00007.png and b/tests/zemu/snapshots/nanos_eip191_opensea/00007.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00008.png b/tests/zemu/snapshots/nanos_eip191_opensea/00008.png index f5c2d67..d5c4fde 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_opensea/00008.png and b/tests/zemu/snapshots/nanos_eip191_opensea/00008.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00009.png b/tests/zemu/snapshots/nanos_eip191_opensea/00009.png index ce795f3..407da90 100644 Binary files a/tests/zemu/snapshots/nanos_eip191_opensea/00009.png and b/tests/zemu/snapshots/nanos_eip191_opensea/00009.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00010.png b/tests/zemu/snapshots/nanos_eip191_opensea/00010.png new file mode 100644 index 0000000..481c8dc Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_opensea/00010.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00011.png b/tests/zemu/snapshots/nanos_eip191_opensea/00011.png new file mode 100644 index 0000000..ff9dba9 Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_opensea/00011.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00012.png b/tests/zemu/snapshots/nanos_eip191_opensea/00012.png new file mode 100644 index 0000000..e179c29 Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_opensea/00012.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00013.png b/tests/zemu/snapshots/nanos_eip191_opensea/00013.png new file mode 100644 index 0000000..f872acc Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_opensea/00013.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00014.png b/tests/zemu/snapshots/nanos_eip191_opensea/00014.png new file mode 100644 index 0000000..f5c2d67 Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_opensea/00014.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00015.png b/tests/zemu/snapshots/nanos_eip191_opensea/00015.png new file mode 100644 index 0000000..d55782f Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_opensea/00015.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00016.png b/tests/zemu/snapshots/nanos_eip191_opensea/00016.png new file mode 100644 index 0000000..f5c2d67 Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_opensea/00016.png differ diff --git a/tests/zemu/snapshots/nanos_eip191_opensea/00017.png b/tests/zemu/snapshots/nanos_eip191_opensea/00017.png new file mode 100644 index 0000000..ce795f3 Binary files /dev/null and b/tests/zemu/snapshots/nanos_eip191_opensea/00017.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_nonascii/00001.png b/tests/zemu/snapshots/nanox_eip191_nonascii/00001.png index 93eda35..6a5f8e8 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_nonascii/00001.png and b/tests/zemu/snapshots/nanox_eip191_nonascii/00001.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_nonascii/00002.png b/tests/zemu/snapshots/nanox_eip191_nonascii/00002.png index 873634e..78d7d1d 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_nonascii/00002.png and b/tests/zemu/snapshots/nanox_eip191_nonascii/00002.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00001.png b/tests/zemu/snapshots/nanox_eip191_opensea/00001.png index 802fad5..4f59a8d 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00001.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00001.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00002.png b/tests/zemu/snapshots/nanox_eip191_opensea/00002.png index a3ba739..c094bc6 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00002.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00002.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00003.png b/tests/zemu/snapshots/nanox_eip191_opensea/00003.png index 4601bca..9a3efb7 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00003.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00003.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00004.png b/tests/zemu/snapshots/nanox_eip191_opensea/00004.png index eab9f1d..657edb5 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00004.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00004.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00005.png b/tests/zemu/snapshots/nanox_eip191_opensea/00005.png index 0b4bdbd..1f135ae 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00005.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00005.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00006.png b/tests/zemu/snapshots/nanox_eip191_opensea/00006.png index c9da92b..952e5ca 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00006.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00006.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00007.png b/tests/zemu/snapshots/nanox_eip191_opensea/00007.png index 121cfd5..f29ed00 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00007.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00007.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00008.png b/tests/zemu/snapshots/nanox_eip191_opensea/00008.png index c9da92b..8af3d9c 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00008.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00008.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00009.png b/tests/zemu/snapshots/nanox_eip191_opensea/00009.png index a58590b..c9da92b 100644 Binary files a/tests/zemu/snapshots/nanox_eip191_opensea/00009.png and b/tests/zemu/snapshots/nanox_eip191_opensea/00009.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00010.png b/tests/zemu/snapshots/nanox_eip191_opensea/00010.png new file mode 100644 index 0000000..121cfd5 Binary files /dev/null and b/tests/zemu/snapshots/nanox_eip191_opensea/00010.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00011.png b/tests/zemu/snapshots/nanox_eip191_opensea/00011.png new file mode 100644 index 0000000..c9da92b Binary files /dev/null and b/tests/zemu/snapshots/nanox_eip191_opensea/00011.png differ diff --git a/tests/zemu/snapshots/nanox_eip191_opensea/00012.png b/tests/zemu/snapshots/nanox_eip191_opensea/00012.png new file mode 100644 index 0000000..a58590b Binary files /dev/null and b/tests/zemu/snapshots/nanox_eip191_opensea/00012.png differ diff --git a/tests/zemu/src/eip191.test.js b/tests/zemu/src/eip191.test.js index 2223256..c54b013 100644 --- a/tests/zemu/src/eip191.test.js +++ b/tests/zemu/src/eip191.test.js @@ -34,7 +34,7 @@ nano_models.forEach(function(model) { await waitForAppScreen(sim); - const rclicks = (model.letter == 'S') ? 6 : 4; + const rclicks = (model.letter == 'S') ? 8 : 4; await sim.navigateAndCompareSnapshots('.', model.name + '_eip191_nonascii', [rclicks, -1, 0]); await expect(tx).resolves.toEqual({ @@ -54,7 +54,14 @@ nano_models.forEach(function(model) { await waitForAppScreen(sim); - await sim.navigateAndCompareSnapshots('.', model.name + '_eip191_opensea', [7, -1, 0]); + if (model.letter == 'S') + { + await sim.navigateAndCompareSnapshots('.', model.name + '_eip191_opensea', [1, 5, 1, 6, 0, 1, -1, 0]); + } + else + { + await sim.navigateAndCompareSnapshots('.', model.name + '_eip191_opensea', [1, 5, 1, 2, 1, -1, 0]); + } await expect(tx).resolves.toEqual({ "v": 28,