diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 86d7288..5c2c5b3 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -3,18 +3,18 @@ name: Compilation & tests on: push: branches: - - master + - master pull_request: branches: - - master + - master jobs: - job_build_debug: - name: Build debug + job_build_debug_nano_s: + name: Build debug Nano S runs-on: ubuntu-latest container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:2.0.0-1 + image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest steps: - name: Clone @@ -24,21 +24,113 @@ jobs: - name: Build an altcoin run: | - make DEBUG=1 CHAIN=ethereum_classic + make DEBUG=1 ALLOW_DATA=1 CHAIN=ethereum_classic + mv bin/app.elf ethereum_classic_nanos.elf - name: Upload altcoin binary uses: actions/upload-artifact@v2 with: - name: ethereum-classic-app-debug - path: bin + name: ethereum_classic_nanos + path: ./ethereum_classic_nanos.elf - name: Build Ethereum run: | make clean - make DEBUG=1 + make DEBUG=1 ALLOW_DATA=1 + mv bin/app.elf ethereum_nanos.elf - name: Upload app binary uses: actions/upload-artifact@v2 with: - name: ethereum-app-debug - path: bin + name: ethereum_nanos + path: ./ethereum_nanos.elf + + job_build_debug_nano_x: + name: Build debug Nano X + runs-on: ubuntu-latest + + container: + image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest + + steps: + - name: Clone + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Build an altcoin Nano X + run: | + make clean + make BOLOS_SDK=$NANOX_SDK DEBUG=1 ALLOW_DATA=1 CHAIN=ethereum_classic + mv bin/app.elf ethereum_classic_nanox.elf + + - name: Upload altcoin binary + uses: actions/upload-artifact@v2 + with: + name: ethereum_classic_nanox + path: ./ethereum_classic_nanox.elf + + - name: Build Ethereum Nano X + run: | + make clean + make BOLOS_SDK=$NANOX_SDK DEBUG=1 ALLOW_DATA=1 + mv bin/app.elf ethereum_nanox.elf + + - name: Upload app binary + uses: actions/upload-artifact@v2 + with: + name: ethereum_nanox + path: ./ethereum_nanox.elf + + scan-build: + name: Clang Static Analyzer + runs-on: ubuntu-latest + + container: + image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest + + steps: + - uses: actions/checkout@v2 + + - name: Build with Clang Static Analyzer + run: | + make clean + scan-build --use-cc=clang -analyze-headers -enable-checker security -enable-checker unix -enable-checker valist -o scan-build --status-bugs make default + - uses: actions/upload-artifact@v2 + if: failure() + with: + name: scan-build + path: scan-build + + jobs-e2e-tests: + needs: [job_build_debug_nano_s, job_build_debug_nano_x] + runs-on: ubuntu-latest + steps: + - name: Test + run: | + id + echo $HOME + echo $DISPLAY + - name: Checkout + uses: actions/checkout@v2 + - run: sudo apt-get update -y && sudo apt-get install -y libusb-1.0.0 libudev-dev + - name: Install node + uses: actions/setup-node@v2 + with: + node-version: "14.4.0" + - name: Install yarn + run: | + npm install -g yarn + - name: Build/Install build js deps + run: | + cd tests && yarn install + - name: Download app binaries + uses: actions/download-artifact@v2 + with: + path: tests/elfs + - name: Gather elfs + run: | + cp `find . -name "*.elf"` ./tests/elfs + - name: Run zemu tests + run: | + cd tests && yarn test diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml deleted file mode 100644 index a19b336..0000000 --- a/.github/workflows/e2e-tests.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: End-to-end tests - -on: - push: - branches: - - master - pull_request: - branches: - - master - -jobs: - e2e-tests: - runs-on: ubuntu-latest - steps: - - name: Test - run: | - id - echo $HOME - echo $DISPLAY - - name: Checkout - uses: actions/checkout@v2 - - run: sudo apt-get update -y && sudo apt-get install -y libusb-1.0.0 libudev-dev - - name: Install node - uses: actions/setup-node@v2 - with: - node-version: '14.4.0' - - name: Install yarn - run: | - npm install -g yarn - - name: Build/Install build js deps - run: | - cd tests && yarn install - - name: Run zemu tests - run: | - cd tests && yarn test \ No newline at end of file diff --git a/.gitignore b/.gitignore index e388d15..1138673 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ tests/node_modules tests/lib tests/yarn-error.log + +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 773668e..1e3da2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,43 +5,72 @@ 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.8.8](https://github.com/ledgerhq/app-ethereum/compare/1.8.7...1.8.8) - 2021-7-21 + +### Added + +- Added support for BSC. +- Add support for Lido plugin + +## [1.8.7](https://github.com/ledgerhq/app-ethereum/compare/1.8.6...1.8.7) - 2021-7-9 + +### Added + +Plugins can now check the address of the transaction sender. +Remove `m/44'/60'` derivation path authorisation for Theta app. + +### Fixed + +`additional_screens` was introduced previously but wasn't properly initialized in some cases. + +## [1.8.6](https://github.com/ledgerhq/app-ethereum/compare/1.8.5...1.8.6) - 2021-7-5 + +### Added + +Display the name of the network when signing a transaction, or the chain ID if the network is not known +When the network is known, amounts and fees are displayed in the network unit instead of ETH. + +### Fixed + +Fix some compilation warning + ## [1.8.5](https://github.com/ledgerhq/app-ethereum/compare/1.7.9...1.8.5) - 2021-6-8 ### Added -Added support for external plugins. +- Added support for external plugins. ## [1.7.9](https://github.com/ledgerhq/app-ethereum/compare/1.7.8...1.7.9) - 2021-6-2 ### Added -Added support for Flare Network and Theta Chain. +- Added support for Flare Network and Theta Chain. ## [1.7.8](https://github.com/ledgerhq/app-ethereum/compare/1.7.7...1.7.8) - 2021-5-20 ### Fixed -Fixed a bug where transaction would sometimes not get properly signed. +- Fixed a bug where transaction would sometimes not get properly signed. ## [1.7.7](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.7) - 2021-5-19 ### Special -Version bump needed for deployment reasons, nothing changed. +- Version bump needed for deployment reasons, nothing changed. ## [1.7.6](https://github.com/ledgerhq/app-ethereum/compare/1.7.5...1.7.6) - 2021-5-14 ### Special -Version bump needed for deployment reasons, nothing changed. +- Version bump needed for deployment reasons, nothing changed. ## [1.7.7](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.7) - 2021-5-19 -N/A +- N/A ## [1.7.6](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.6) - 2021-5-14 -N/A +- N/A ## [1.7.5](https://github.com/ledgerhq/app-ethereum/compare/1.7.4...1.7.5) - 2021-5-10 @@ -66,9 +95,9 @@ N/A ### Added - Improve Ethereum 2 deposit security: - - Display the validator address on screen when depositing. - - Abort signing when the account index of the withdrawal key is higher than INDEX_MAX. - - Check that the destination field of the transaction is Ethereum 2 deposit contract. + - Display the validator address on screen when depositing. + - Abort signing when the account index of the withdrawal key is higher than INDEX_MAX. + - Check that the destination field of the transaction is Ethereum 2 deposit contract. ## [1.7.1](https://github.com/ledgerhq/app-ethereum/compare/1.7.0...1.7.1) - 2021-5-5 @@ -76,21 +105,25 @@ N/A - Support for Berlin hard fork: EIP2718 (transaction types) and EIP2930 (access list transactions) - Display ChainID when transacting on chains which are not ethereum (BSC, Polygon, etc) + ## [1.7.0](https://github.com/ledgerhq/app-ethereum/compare/1.6.6...1.7.0) - 2021-4-30 ### Added - Wallet ID feature now available on Nano X + ## [1.6.6](https://github.com/ledgerhq/app-ethereum/compare/1.6.5...1.6.6) - 2021-4-16 ### Added - Improved Starkware support + ## [1.6.5](https://github.com/ledgerhq/app-ethereum/compare/1.6.4...1.6.5) - 2021-2-12 ### Added - Add a setting to enable nonce display when approving transactions + ## [1.6.4](https://github.com/ledgerhq/app-ethereum/compare/1.6.3...1.6.4) - 2021-1-12 ### Fixed diff --git a/Makefile b/Makefile index bfd27bf..93bd78d 100755 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'" APPVERSION_M=1 APPVERSION_N=8 -APPVERSION_P=5 +APPVERSION_P=8 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION) @@ -41,7 +41,7 @@ endif ifeq ($(CHAIN),ethereum) # Lock the application on its standard path for 1.5. Please complain if non compliant APP_LOAD_PARAMS += --path "44'/60'" -DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=0 +DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=1 # Starkware integration APP_LOAD_PARAMS += --path "2645'/579218131'" DEFINES += HAVE_STARKWARE @@ -197,9 +197,13 @@ APP_LOAD_PARAMS += --path "44'/554'" --path "44'/60'" DEFINES += CHAINID_UPCASE=\"FLARE\" CHAINID_COINNAME=\"FLR\" CHAIN_KIND=CHAIN_KIND_FLARE CHAIN_ID=16 APPNAME = "Flare Coston" else ifeq ($(CHAIN),theta) -APP_LOAD_PARAMS += --path "44'/500'" --path "44'/60'" +APP_LOAD_PARAMS += --path "44'/500'" DEFINES += CHAINID_UPCASE=\"THETA\" CHAINID_COINNAME=\"THETA\" CHAIN_KIND=CHAIN_KIND_THETA CHAIN_ID=500 APPNAME = "Theta" +else ifeq ($(CHAIN),bsc) +APP_LOAD_PARAMS += --path "44'/60'" +DEFINES += CHAINID_UPCASE=\"BSC\" CHAINID_COINNAME=\"BNB\" CHAIN_KIND=CHAIN_KIND_BSC CHAIN_ID=56 +APPNAME = "Binance Smart Chain" else ifeq ($(filter clean,$(MAKECMDGOALS)),) $(error Unsupported CHAIN - use ethereum, ropsten, ethereum_classic, expanse, poa, artis_sigma1, artis_tau1, rsk, rsk_testnet, ubiq, wanchain, kusd, musicoin, pirl, akroma, atheios, callisto, ethersocial, ellaism, ether1, ethergem, gochain, mix, reosc, hpb, tomochain, tobalaba, dexon, volta, ewc, webchain, thundercore, flare, flare_coston, theta) @@ -266,6 +270,12 @@ ifneq ($(ALLOW_DATA),0) DEFINES += HAVE_ALLOW_DATA endif +# Bypass the signature verification for setExternalPlugin and provideERC20TokenInfo calls +BYPASS_SIGNATURES:=0 +ifneq ($(BYPASS_SIGNATURES),0) +DEFINES += HAVE_BYPASS_SIGNATURES +endif + # Enabling debug PRINTF DEBUG:=0 @@ -306,7 +316,7 @@ endif CC := $(CLANGPATH)clang #CFLAGS += -O0 -CFLAGS += -O3 -Os -Wno-format-invalid-specifier -Wno-format-extra-args -Wno-main +CFLAGS += -O3 -Os -Wno-format-invalid-specifier -Wno-format-extra-args AS := $(GCCPATH)arm-none-eabi-gcc @@ -334,6 +344,7 @@ endif # rebuild $(shell python3 ethereum-plugin-sdk/build_sdk.py) +$(shell find ./ethereum-plugin-sdk -iname '*.h' -o -iname '*.c' | xargs clang-format-10 -i) # check if a difference is noticed (fail if it happens in CI build) ifneq ($(shell git status | grep 'ethereum-plugin-sdk'),) @@ -366,4 +377,4 @@ include $(BOLOS_SDK)/Makefile.rules dep/%.d: %.c Makefile listvariants: - @echo VARIANTS CHAIN ethereum ropsten ethereum_classic expanse poa rsk rsk_testnet ubiq wanchain pirl akroma atheios callisto ethersocial ether1 gochain musicoin ethergem mix ellaism reosc hpb tomochain dexon volta ewc thundercore flare flare_coston theta + @echo VARIANTS CHAIN ethereum ropsten ethereum_classic expanse poa rsk rsk_testnet ubiq wanchain pirl akroma atheios callisto ethersocial ether1 gochain musicoin ethergem mix ellaism reosc hpb tomochain dexon volta ewc thundercore flare flare_coston theta bsc diff --git a/README.md b/README.md index c82e7a4..be33471 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,13 @@ Ethereum wallet application framework for Nano S and Nano X. Ledger Blue is not maintained anymore, but the app can still be compiled for this target using the branch `blue-final-release`. -This app follows the specification available in the `doc/` folder +This app follows the specification available in the `doc/` folder. -To compile it and load it on a device, have a look here: https://ledger.readthedocs.io/en/latest/userspace/getting_started.html +To compile it and load it on a device, please check out our [developer portal](https://developers.ledger.com/docs/NA/start_here/). + +# Plugins + +This app support external plugins. More info in [doc/ethapp_plugin.asc](https://github.com/LedgerHQ/app-ethereum/blob/master/doc/ethapp_plugins.asc). If you wish to have a look at an existing plugin, feel free to check out the [ParaSwap plugin](https://github.com/LedgerHQ/app-plugin-paraswap). # Testing @@ -55,5 +59,4 @@ Then copy the binary to the `tests/elfs` folder (in this case, compiled with SDK cp bin/app.elf tests/elfs/ethereum_nanos.elf ``` -Repeat the operation for a binary compiled with nanoX SDK and change for `ethereum_nanox.elf`. - +Repeat the operation for a binary compiled with nanoX SDK and change for `ethereum_nanox.elf`. \ No newline at end of file diff --git a/doc/ethapp_plugins.asc b/doc/ethapp_plugins.asc index 5b67b68..33b079d 100644 --- a/doc/ethapp_plugins.asc +++ b/doc/ethapp_plugins.asc @@ -13,6 +13,8 @@ Specification version 1.0 - 24th of September 2020 This specification describes the plugin interface used to display a specific UI on device for Ethereum smart contracts. +Feel free to checkout the ParaSwap plugin to see an actual implementation. Link: https://github.com/LedgerHQ/app-ethereum/blob/named-external-plugins/doc/ethapp_plugins.asc . + ## Flow overview When signing an Ethereum transaction containing data, the Ethereum application looks for a plugin using .either a selector list or the contract address. @@ -149,7 +151,7 @@ typedef struct ethPluginFinalize_t { uint8_t *tokenLookup2; uint8_t *amount; // set an uint256 pointer if uiType is UI_AMOUNT_ADDRESS - uint8_t *address; // set to a 20 bytes address pointer if uiType is UI_AMOUNT_ADDRESS + uint8_t *address; // set to the destination address if uiType is UI_AMOUNT_ADDRESS. Set to the user's address if uiType is UI_TYPE_GENERIC uint8_t uiType; uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS @@ -282,7 +284,7 @@ The following return codes are expected, any other will abort the signing proces When setting a pointer from the plugin space, make sure to use an address that will be accessible from the Ethereum application (typically in the plugin RAM context, *not* on the plugin stack) -Do not use data types that need to be aligned (such as uint32_t) in the plugin context +Do not use data types that need to be aligned (such as uint32_t) in the plugin context. ## TODOs diff --git a/ethereum-plugin-sdk b/ethereum-plugin-sdk index a232fcd..b5325d0 160000 --- a/ethereum-plugin-sdk +++ b/ethereum-plugin-sdk @@ -1 +1 @@ -Subproject commit a232fcd3ca8f3f5ee3c23af16b7621c7604c65a7 +Subproject commit b5325d0f08af7f233e22d766183fb70cdb8ead59 diff --git a/examples/ethBase.py b/examples/ethBase.py index b66b116..4fc1998 100755 --- a/examples/ethBase.py +++ b/examples/ethBase.py @@ -59,6 +59,9 @@ class UnsignedTransaction(Serializable): ('to', address), ('value', big_endian_int), ('data', binary), + ('chainid', big_endian_int), + ('dummy1', big_endian_int), + ('dummy2', big_endian_int), ] def unsigned_tx_from_tx(tx): diff --git a/examples/signTx.py b/examples/signTx.py index 5bb7c34..527c0ce 100755 --- a/examples/signTx.py +++ b/examples/signTx.py @@ -77,6 +77,10 @@ if args.data == None: else: args.data = decode_hex(args.data[2:]) +# default to Ethereum mainnet +if args.chainid == None: + args.chainid = 1 + amount = Decimal(args.amount) * 10**18 tx = UnsignedTransaction( @@ -86,11 +90,17 @@ tx = UnsignedTransaction( to=decode_hex(args.to[2:]), value=int(amount), data=args.data, + chainid=args.chainid, + dummy1=0, + dummy2=0 ) encodedTx = encode(tx, UnsignedTransaction) -encodedTx = bytearray.fromhex( - "02ef0306843b9aca008504a817c80082520894b2bb2b958afa2e96dab3f3ce7162b87daea39017872386f26fc1000080c0") +# encodedTx = bytearray.fromhex( +# "02ef0306843b9aca008504a817c80082520894b2bb2b958afa2e96dab3f3ce7162b87daea39017872386f26fc1000080c0") + +# To test an EIP-2930 transaction, uncomment this line +#encodedTx = bytearray.fromhex("01f8e60380018402625a0094cccccccccccccccccccccccccccccccccccccccc830186a0a4693c61390000000000000000000000000000000000000000000000000000000000000002f85bf859940000000000000000000000000000000000000102f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000060a780a09b8adcd2a4abd34b42d56fcd90b949f74ca9696dfe2b427bc39aa280bbf1924ca029af4a471bb2953b4e7933ea95880648552a9345424a1ac760189655ceb1832a") dongle = getDongle(True) diff --git a/icons/nanos_app_bsc.gif b/icons/nanos_app_bsc.gif new file mode 100644 index 0000000..4154097 Binary files /dev/null and b/icons/nanos_app_bsc.gif differ diff --git a/icons/nanox_app_bsc.gif b/icons/nanox_app_bsc.gif new file mode 100644 index 0000000..0f3cc96 Binary files /dev/null and b/icons/nanox_app_bsc.gif differ diff --git a/src/chainConfig.h b/src/chainConfig.h index 4cbd5ab..a845018 100644 --- a/src/chainConfig.h +++ b/src/chainConfig.h @@ -54,7 +54,8 @@ typedef enum chain_kind_e { CHAIN_KIND_WEBCHAIN, CHAIN_KIND_THUNDERCORE, CHAIN_KIND_FLARE, - CHAIN_KIND_THETA + CHAIN_KIND_THETA, + CHAIN_KIND_BSC } chain_kind_t; typedef struct chain_config_s { diff --git a/src/eth_plugin_handler.c b/src/eth_plugin_handler.c index da1cac9..725469c 100644 --- a/src/eth_plugin_handler.c +++ b/src/eth_plugin_handler.c @@ -21,12 +21,8 @@ void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize) { memset((uint8_t *) finalize, 0, sizeof(ethPluginFinalize_t)); } -void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken, - tokenDefinition_t *token1, - tokenDefinition_t *token2) { +void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken) { memset((uint8_t *) provideToken, 0, sizeof(ethPluginProvideToken_t)); - provideToken->token1 = token1; - provideToken->token2 = token2; } void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID, @@ -67,11 +63,19 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress, if (memcmp(contractAddress, dataContext.tokenContext.contract_address, sizeof(dataContext.tokenContext.contract_address)) != 0) { + PRINTF("Got contract: %.*H\n", ADDRESS_LENGTH, contractAddress); + PRINTF("Expected contract: %.*H\n", + ADDRESS_LENGTH, + dataContext.tokenContext.contract_address); os_sched_exit(0); } if (memcmp(init->selector, dataContext.tokenContext.method_selector, sizeof(dataContext.tokenContext.method_selector)) != 0) { + PRINTF("Got selector: %.*H\n", SELECTOR_SIZE, init->selector); + PRINTF("Expected selector: %.*H\n", + SELECTOR_SIZE, + dataContext.tokenContext.method_selector); os_sched_exit(0); } PRINTF("External plugin will be used\n"); @@ -90,7 +94,9 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress, if (memcmp(init->selector, (const void *) PIC(selectors[j]), SELECTOR_SIZE) == 0) { if ((INTERNAL_ETH_PLUGINS[i].availableCheck == NULL) || ((PluginAvailableCheck) PIC(INTERNAL_ETH_PLUGINS[i].availableCheck))()) { - strcpy(dataContext.tokenContext.pluginName, INTERNAL_ETH_PLUGINS[i].alias); + strlcpy(dataContext.tokenContext.pluginName, + INTERNAL_ETH_PLUGINS[i].alias, + PLUGIN_ID_LENGTH); dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK; contractAddress = NULL; break; @@ -128,7 +134,6 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress, eth_plugin_result_t eth_plugin_call(int method, void *parameter) { ethPluginSharedRW_t pluginRW; ethPluginSharedRO_t pluginRO; - char tmp[PLUGIN_ID_LENGTH]; char *alias; uint8_t i; uint8_t internalPlugin = 0; @@ -146,6 +151,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { switch (method) { case ETH_PLUGIN_INIT_CONTRACT: + PRINTF("-- PLUGIN INIT CONTRACT --\n"); ((ethPluginInitContract_t *) parameter)->interfaceVersion = ETH_PLUGIN_INTERFACE_VERSION_1; ((ethPluginInitContract_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; @@ -158,6 +164,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { ((ethPluginInitContract_t *) parameter)->alias = dataContext.tokenContext.pluginName; break; case ETH_PLUGIN_PROVIDE_PARAMETER: + PRINTF("-- PLUGIN PROVIDE PARAMETER --\n"); ((ethPluginProvideParameter_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethPluginProvideParameter_t *) parameter)->pluginSharedRW = &pluginRW; ((ethPluginProvideParameter_t *) parameter)->pluginSharedRO = &pluginRO; @@ -165,6 +172,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { (uint8_t *) &dataContext.tokenContext.pluginContext; break; case ETH_PLUGIN_FINALIZE: + PRINTF("-- PLUGIN FINALIZE --\n"); ((ethPluginFinalize_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethPluginFinalize_t *) parameter)->pluginSharedRW = &pluginRW; ((ethPluginFinalize_t *) parameter)->pluginSharedRO = &pluginRO; @@ -172,6 +180,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { (uint8_t *) &dataContext.tokenContext.pluginContext; break; case ETH_PLUGIN_PROVIDE_TOKEN: + PRINTF("-- PLUGIN PROVIDE TOKEN --\n"); ((ethPluginProvideToken_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethPluginProvideToken_t *) parameter)->pluginSharedRW = &pluginRW; ((ethPluginProvideToken_t *) parameter)->pluginSharedRO = &pluginRO; @@ -179,6 +188,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { (uint8_t *) &dataContext.tokenContext.pluginContext; break; case ETH_PLUGIN_QUERY_CONTRACT_ID: + PRINTF("-- PLUGIN QUERY CONTRACT ID --\n"); ((ethQueryContractID_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethQueryContractID_t *) parameter)->pluginSharedRW = &pluginRW; ((ethQueryContractID_t *) parameter)->pluginSharedRO = &pluginRO; @@ -186,6 +196,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { (uint8_t *) &dataContext.tokenContext.pluginContext; break; case ETH_PLUGIN_QUERY_CONTRACT_UI: + PRINTF("-- PLUGIN QUERY CONTRACT UI --\n"); ((ethQueryContractUI_t *) parameter)->pluginSharedRW = &pluginRW; ((ethQueryContractUI_t *) parameter)->pluginSharedRO = &pluginRO; ((ethQueryContractUI_t *) parameter)->pluginContext = @@ -231,7 +242,6 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { PRINTF("method: %d\n", method); switch (method) { case ETH_PLUGIN_INIT_CONTRACT: - PRINTF("parameter result: %d\n", ((ethPluginInitContract_t *) parameter)->result); switch (((ethPluginInitContract_t *) parameter)->result) { case ETH_PLUGIN_RESULT_OK: break; @@ -264,6 +274,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { } break; case ETH_PLUGIN_PROVIDE_TOKEN: + PRINTF("RESULT: %d\n", ((ethPluginProvideToken_t *) parameter)->result); switch (((ethPluginProvideToken_t *) parameter)->result) { case ETH_PLUGIN_RESULT_OK: case ETH_PLUGIN_RESULT_FALLBACK: @@ -280,7 +291,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) { } break; case ETH_PLUGIN_QUERY_CONTRACT_UI: - if (((ethQueryContractUI_t *) parameter)->result <= ETH_PLUGIN_RESULT_OK) { + if (((ethQueryContractUI_t *) parameter)->result <= ETH_PLUGIN_RESULT_UNSUCCESSFUL) { return ETH_PLUGIN_RESULT_UNAVAILABLE; } break; diff --git a/src/eth_plugin_handler.h b/src/eth_plugin_handler.h index 05d7649..8c86af3 100644 --- a/src/eth_plugin_handler.h +++ b/src/eth_plugin_handler.h @@ -7,9 +7,7 @@ void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *providePa uint8_t *parameter, uint32_t parameterOffset); void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize); -void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken, - tokenDefinition_t *token1, - tokenDefinition_t *token2); +void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken); void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID, char *name, uint32_t nameLength, diff --git a/src/eth_plugin_interface.h b/src/eth_plugin_interface.h index 556e348..2698e21 100644 --- a/src/eth_plugin_interface.h +++ b/src/eth_plugin_interface.h @@ -105,7 +105,8 @@ typedef struct ethPluginFinalize_t { uint8_t *tokenLookup2; uint8_t *amount; // set an uint256 pointer if uiType is UI_AMOUNT_ADDRESS - uint8_t *address; // set to a 20 bytes address pointer if uiType is UI_AMOUNT_ADDRESS + uint8_t *address; // set to the destination address if uiType is UI_AMOUNT_ADDRESS. Set to the + // user's address if uiType is UI_TYPE_GENERIC uint8_t uiType; uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS diff --git a/src/eth_plugin_internal.c b/src/eth_plugin_internal.c index d4d573f..1ed45cd 100644 --- a/src/eth_plugin_internal.c +++ b/src/eth_plugin_internal.c @@ -13,23 +13,20 @@ void starkware_plugin_call(int message, void* parameters); void eth2_plugin_call(int message, void* parameters); #endif -static const uint8_t const ERC20_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0xa9, 0x05, 0x9c, 0xbb}; -static const uint8_t const ERC20_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3}; +static const uint8_t ERC20_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0xa9, 0x05, 0x9c, 0xbb}; +static const uint8_t ERC20_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3}; const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = {ERC20_TRANSFER_SELECTOR, ERC20_APPROVE_SELECTOR}; -static const uint8_t const ERC721_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3}; +static const uint8_t ERC721_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3}; const uint8_t* const ERC721_SELECTORS[NUM_ERC721_SELECTORS] = {ERC721_APPROVE_SELECTOR}; -static const uint8_t const COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = {0x85, - 0x2a, - 0x12, - 0xe3}; -static const uint8_t const COMPOUND_REDEEM_SELECTOR[SELECTOR_SIZE] = {0xdb, 0x00, 0x6a, 0x75}; -static const uint8_t const COMPOUND_MINT_SELECTOR[SELECTOR_SIZE] = {0xa0, 0x71, 0x2d, 0x68}; -static const uint8_t const CETH_MINT_SELECTOR[SELECTOR_SIZE] = {0x12, 0x49, 0xc5, 0x8b}; +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, @@ -39,7 +36,7 @@ const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = { #ifdef HAVE_ETH2 -static const uint8_t const ETH2_DEPOSIT_SELECTOR[SELECTOR_SIZE] = {0x22, 0x89, 0x51, 0x18}; +static const uint8_t ETH2_DEPOSIT_SELECTOR[SELECTOR_SIZE] = {0x22, 0x89, 0x51, 0x18}; const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = {ETH2_DEPOSIT_SELECTOR}; @@ -47,39 +44,33 @@ const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = {ETH2_DEPOSIT_SELECTOR #ifdef HAVE_STARKWARE -static const uint8_t const STARKWARE_REGISTER_ID[SELECTOR_SIZE] = {0xdd, 0x24, 0x14, 0xd4}; -static const uint8_t const STARKWARE_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x25, 0x05, 0xc3, 0xd9}; -static const uint8_t const STARKWARE_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x00, 0xae, 0xef, 0x8a}; -static const uint8_t const STARKWARE_DEPOSIT_CANCEL_ID[SELECTOR_SIZE] = {0x7d, 0xf7, 0xdc, 0x04}; -static const uint8_t const STARKWARE_DEPOSIT_RECLAIM_ID[SELECTOR_SIZE] = {0xae, 0x87, 0x38, 0x16}; -static const uint8_t const STARKWARE_WITHDRAW_ID[SELECTOR_SIZE] = {0x44, 0x1a, 0x3e, 0x70}; -static const uint8_t const STARKWARE_FULL_WITHDRAWAL_ID[SELECTOR_SIZE] = {0xa9, 0x33, 0x10, 0xc4}; -static const uint8_t const STARKWARE_FREEZE_ID[SELECTOR_SIZE] = {0x93, 0xc1, 0xe4, 0x66}; -static const uint8_t const STARKWARE_ESCAPE_ID[SELECTOR_SIZE] = {0x9e, 0x3a, 0xda, 0xc4}; -static const uint8_t const STARKWARE_VERIFY_ESCAPE_ID[SELECTOR_SIZE] = {0x2d, 0xd5, 0x30, 0x06}; +static const uint8_t STARKWARE_REGISTER_ID[SELECTOR_SIZE] = {0xdd, 0x24, 0x14, 0xd4}; +static const uint8_t STARKWARE_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x25, 0x05, 0xc3, 0xd9}; +static const uint8_t STARKWARE_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x00, 0xae, 0xef, 0x8a}; +static const uint8_t STARKWARE_DEPOSIT_CANCEL_ID[SELECTOR_SIZE] = {0x7d, 0xf7, 0xdc, 0x04}; +static const uint8_t STARKWARE_DEPOSIT_RECLAIM_ID[SELECTOR_SIZE] = {0xae, 0x87, 0x38, 0x16}; +static const uint8_t STARKWARE_WITHDRAW_ID[SELECTOR_SIZE] = {0x44, 0x1a, 0x3e, 0x70}; +static const uint8_t STARKWARE_FULL_WITHDRAWAL_ID[SELECTOR_SIZE] = {0xa9, 0x33, 0x10, 0xc4}; +static const uint8_t STARKWARE_FREEZE_ID[SELECTOR_SIZE] = {0x93, 0xc1, 0xe4, 0x66}; +static const uint8_t STARKWARE_ESCAPE_ID[SELECTOR_SIZE] = {0x9e, 0x3a, 0xda, 0xc4}; +static const uint8_t STARKWARE_VERIFY_ESCAPE_ID[SELECTOR_SIZE] = {0x2d, 0xd5, 0x30, 0x06}; -static const uint8_t const STARKWARE_WITHDRAW_TO_ID[SELECTOR_SIZE] = {0x14, 0xcd, 0x70, 0xe4}; -static const uint8_t const STARKWARE_DEPOSIT_NFT_ID[SELECTOR_SIZE] = {0xae, 0x1c, 0xdd, 0xe6}; -static const uint8_t const STARKWARE_DEPOSIT_NFT_RECLAIM_ID[SELECTOR_SIZE] = {0xfc, - 0xb0, - 0x58, - 0x22}; -static const uint8_t const STARKWARE_WITHDRAW_AND_MINT_ID[SELECTOR_SIZE] = {0xd9, 0x14, 0x43, 0xb7}; -static const uint8_t const STARKWARE_WITHDRAW_NFT_ID[SELECTOR_SIZE] = {0x01, 0x9b, 0x41, 0x7a}; -static const uint8_t const STARKWARE_WITHDRAW_NFT_TO_ID[SELECTOR_SIZE] = {0xeb, 0xef, 0x0f, 0xd0}; -static const uint8_t const STARKWARE_REGISTER_AND_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x10, - 0x82, - 0x08, - 0xcf}; -static const uint8_t const STARKWARE_REGISTER_AND_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0xa7, - 0x78, - 0xc0, - 0xc3}; -static const uint8_t const STARKWARE_PROXY_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0xdc, - 0xca, - 0xd5, - 0x24}; -static const uint8_t const STARKWARE_PROXY_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x6c, 0xe5, 0xd9, 0x57}; +static const uint8_t STARKWARE_WITHDRAW_TO_ID[SELECTOR_SIZE] = {0x14, 0xcd, 0x70, 0xe4}; +static const uint8_t STARKWARE_DEPOSIT_NFT_ID[SELECTOR_SIZE] = {0xae, 0x1c, 0xdd, 0xe6}; +static const uint8_t STARKWARE_DEPOSIT_NFT_RECLAIM_ID[SELECTOR_SIZE] = {0xfc, 0xb0, 0x58, 0x22}; +static const uint8_t STARKWARE_WITHDRAW_AND_MINT_ID[SELECTOR_SIZE] = {0xd9, 0x14, 0x43, 0xb7}; +static const uint8_t STARKWARE_WITHDRAW_NFT_ID[SELECTOR_SIZE] = {0x01, 0x9b, 0x41, 0x7a}; +static const uint8_t STARKWARE_WITHDRAW_NFT_TO_ID[SELECTOR_SIZE] = {0xeb, 0xef, 0x0f, 0xd0}; +static const uint8_t STARKWARE_REGISTER_AND_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x10, + 0x82, + 0x08, + 0xcf}; +static const uint8_t STARKWARE_REGISTER_AND_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0xa7, + 0x78, + 0xc0, + 0xc3}; +static const uint8_t STARKWARE_PROXY_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0xdc, 0xca, 0xd5, 0x24}; +static const uint8_t STARKWARE_PROXY_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x6c, 0xe5, 0xd9, 0x57}; const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = { STARKWARE_REGISTER_ID, @@ -107,7 +98,7 @@ const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = { // All internal alias names start with 'minus' -const internalEthPlugin_t const INTERNAL_ETH_PLUGINS[] = { +const internalEthPlugin_t INTERNAL_ETH_PLUGINS[] = { {erc20_plugin_available_check, (const uint8_t**) ERC20_SELECTORS, NUM_ERC20_SELECTORS, diff --git a/src/handle_check_address.c b/src/handle_check_address.c index afe9aa7..7686205 100644 --- a/src/handle_check_address.c +++ b/src/handle_check_address.c @@ -59,7 +59,7 @@ int handle_check_address(check_address_parameters_t* params, chain_config_t* cha cx_ecfp_generate_pair(CX_CURVE_256K1, &locals_union2.publicKey, &locals_union1.privateKey, 1); ZERO(locals_union1); getEthAddressStringFromKey(&locals_union2.publicKey, - (uint8_t*) locals_union1.address, + locals_union1.address, &local_sha3, chain_config); ZERO(locals_union2); diff --git a/src/handle_swap_sign_transaction.c b/src/handle_swap_sign_transaction.c index 63a6c36..d610e9e 100644 --- a/src/handle_swap_sign_transaction.c +++ b/src/handle_swap_sign_transaction.c @@ -10,7 +10,7 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti // We need this "trick" as the input data position can overlap with app-ethereum globals txStringProperties_t stack_data; memset(&stack_data, 0, sizeof(stack_data)); - strncpy(stack_data.fullAddress, + strlcpy(stack_data.fullAddress, sign_transaction_params->destination_address, sizeof(stack_data.fullAddress)); if ((stack_data.fullAddress[sizeof(stack_data.fullAddress) - 1] != '\0') || @@ -36,7 +36,7 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti sizeof(stack_data.fullAmount)); // If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap - strcpy(ticker, config->coinName); + strlcpy(ticker, config->coinName, MAX_TICKER_LEN); decimals = WEI_TO_ETHER; amountToString(sign_transaction_params->fee_amount, sign_transaction_params->fee_amount_length, diff --git a/src/main.c b/src/main.c index 2a67cb5..ca26b41 100644 --- a/src/main.c +++ b/src/main.c @@ -92,28 +92,12 @@ void ui_idle(void) { ux_flow_init(0, ux_idle_flow, NULL); } -unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_exit(__attribute__((unused)) const bagl_element_t *e) { // Go back to the dashboard os_sched_exit(0); return 0; // do not redraw the widget } -#if defined(TARGET_NANOS) -unsigned int ui_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: // CANCEL - io_seproxyhal_touch_address_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: { // OK - io_seproxyhal_touch_address_ok(NULL); - break; - } - } - return 0; -} -#endif // #if defined(TARGET_NANOS) - void io_seproxyhal_send_status(uint32_t sw) { G_io_apdu_buffer[0] = ((sw >> 8) & 0xff); G_io_apdu_buffer[1] = (sw & 0xff); @@ -269,6 +253,9 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) { case CHAIN_KIND_THETA: numTokens = NUM_TOKENS_THETA; break; + case CHAIN_KIND_BSC: + numTokens = NUM_TOKENS_BSC; + break; } for (i = 0; i < numTokens; i++) { switch (chainConfig->kind) { @@ -367,6 +354,9 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) { break case CHAIN_KIND_THETA : currentToken = (tokenDefinition_t *) PIC(&TOKENS_THETA[i]); break; + case CHAIN_KIND_BSC: + currentToken = (tokenDefinition_t *) PIC(&TOKENS_BSC[i]); + break; } if (memcmp(currentToken->address, tmpContent.txContent.destination, ADDRESS_LENGTH) == 0) { return currentToken; @@ -385,13 +375,13 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) { return NULL; } +#ifndef HAVE_WALLET_ID_SDK + unsigned int const U_os_perso_seed_cookie[] = { 0xda7aba5e, 0xc1a551c5, }; -#ifndef HAVE_WALLET_ID_SDK - void handleGetWalletId(volatile unsigned int *tx) { unsigned char t[64]; cx_ecfp_256_private_key_t priv; @@ -409,7 +399,7 @@ void handleGetWalletId(volatile unsigned int *tx) { THROW(0x9000); } -#endif +#endif // HAVE_WALLET_ID_SDK void handleApdu(unsigned int *flags, unsigned int *tx) { unsigned short sw = 0; @@ -424,7 +414,7 @@ void handleApdu(unsigned int *flags, unsigned int *tx) { return; } -#endif +#endif // HAVE_WALLET_ID_SDK #ifdef HAVE_STARKWARE @@ -681,7 +671,7 @@ void io_seproxyhal_display(const bagl_element_t *element) { io_seproxyhal_display_default((bagl_element_t *) element); } -unsigned char io_event(unsigned char channel) { +unsigned char io_event(__attribute__((unused)) unsigned char channel) { // nothing done with the event, throw an error on the transport layer if // needed diff --git a/src/shared_context.h b/src/shared_context.h index 7a884b3..e3e9c6f 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -79,7 +79,7 @@ typedef struct tokenContext_t { typedef struct publicKeyContext_t { cx_ecfp_public_key_t publicKey; - uint8_t address[41]; + char address[41]; uint8_t chainCode[INT256_LENGTH]; bool getChaincode; } publicKeyContext_t; @@ -162,13 +162,14 @@ typedef enum { #endif } contract_call_t; +#define NETWORK_NAME_MAX_SIZE 12 + typedef struct txStringProperties_t { char fullAddress[43]; char fullAmount[50]; char maxFee[50]; - char nonce[8]; // 10M tx per account ought to be enough for everybody - char chainID[8]; // 10M different chainID ought to be enough for people to find a unique - // chainID for their token / chain. + char nonce[8]; // 10M tx per account ought to be enough for everybody + char network_name[NETWORK_NAME_MAX_SIZE]; } txStringProperties_t; #define SHARED_CTX_FIELD_1_SIZE 100 diff --git a/src/stark_crypto.c b/src/stark_crypto.c index 9217567..dc4face 100644 --- a/src/stark_crypto.c +++ b/src/stark_crypto.c @@ -60,7 +60,7 @@ void stark_get_amount_string(uint8_t *contractAddress, char *target100) { uint256_t amountPre, quantum, amount; uint8_t decimals; - char *ticker = (char *) PIC(chainConfig->coinName); + char *ticker = chainConfig->coinName; PRINTF("stark_get_amount_string %.*H\n", 20, contractAddress); @@ -81,7 +81,7 @@ void stark_get_amount_string(uint8_t *contractAddress, mul256(&amountPre, &quantum, &amount); tostring256(&amount, 10, tmp100, 100); PRINTF("stark_get_amount_string - mul256 %s\n", tmp100); - strcpy(target100, ticker); + strlcpy(target100, ticker, 100); adjustDecimals(tmp100, strlen(tmp100), target100 + strlen(ticker), 100, decimals); PRINTF("get_amount_string %s\n", target100); } diff --git a/src/tokens.c b/src/tokens.c index c524a3a..63667e8 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -4566,4 +4566,6 @@ const tokenDefinition_t const TOKENS_FLARE[NUM_TOKENS_FLARE] = {}; const tokenDefinition_t const TOKENS_THETA[NUM_TOKENS_THETA] = {}; +const tokenDefinition_t const TOKENS_BSC[NUM_TOKENS_BSC] = {}; + #endif diff --git a/src/tokens.h b/src/tokens.h index 8c69127..3573cd3 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -28,7 +28,7 @@ typedef struct tokenDefinition_t { uint8_t contractName[ADDRESS_LENGTH]; #endif uint8_t address[ADDRESS_LENGTH]; - uint8_t ticker[MAX_TICKER_LEN]; + char ticker[MAX_TICKER_LEN]; uint8_t decimals; } tokenDefinition_t; @@ -43,7 +43,7 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA]; #ifndef HAVE_TOKENS_LIST #ifndef LEDGER_TEST_PUBLIC_KEY -static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = { +static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = { // production key 2019-01-11 03:07PM (erc20signer) 0x04, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x7c, 0x0b, 0x68, 0xcd, 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e, @@ -52,7 +52,7 @@ static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = { 0xcd, 0x09, 0x8f, 0xce, 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83}; #else -static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = { +static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = { // test key 2019-01-11 03:07PM (erc20signer) 0x04, 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1, 0x0f, 0xe4, 0xc3, 0x04, 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e, @@ -96,6 +96,7 @@ static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = { #define NUM_TOKENS_THUNDERCORE 0 #define NUM_TOKENS_FLARE 0 #define NUM_TOKENS_THETA 0 +#define NUM_TOKENS_BSC 0 extern tokenDefinition_t const TOKENS_AKROMA[NUM_TOKENS_AKROMA]; extern tokenDefinition_t const TOKENS_ELLAISM[NUM_TOKENS_ELLAISM]; @@ -129,6 +130,7 @@ extern tokenDefinition_t const TOKENS_WEBCHAIN[NUM_TOKENS_WEBCHAIN]; extern tokenDefinition_t const TOKENS_THUNDERCORE[NUM_TOKENS_THUNDERCORE]; extern tokenDefinition_t const TOKENS_FLARE[NUM_TOKENS_FLARE]; extern tokenDefinition_t const TOKENS_THETA[NUM_TOKENS_THETA]; +extern tokenDefinition_t const TOKENS_BSC[NUM_TOKENS_BSC]; #endif /* HAVE_TOKENS_LIST */ diff --git a/src/ui_flow.c b/src/ui_flow.c index 6bac181..d88732f 100644 --- a/src/ui_flow.c +++ b/src/ui_flow.c @@ -132,11 +132,13 @@ UX_FLOW(ux_settings_flow, &ux_settings_flow_4_step); void display_settings(const ux_flow_step_t* const start_step) { - strcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed")); - strcpy(strings.common.fullAddress + 12, - (N_storage.contractDetails ? "Displayed" : "NOT Displayed")); - strcpy(strings.common.fullAddress + 26, - (N_storage.displayNonce ? "Displayed" : "NOT Displayed")); + strlcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed"), 12); + strlcpy(strings.common.fullAddress + 12, + (N_storage.contractDetails ? "Displayed" : "NOT Displayed"), + 26 - 12); + strlcpy(strings.common.fullAddress + 26, + (N_storage.displayNonce ? "Displayed" : "NOT Displayed"), + sizeof(strings.common.fullAddress) - 26); ux_flow_init(0, ux_settings_flow, start_step); } diff --git a/src/utils.c b/src/utils.c index 401de81..85f2add 100644 --- a/src/utils.c +++ b/src/utils.c @@ -57,20 +57,24 @@ int local_strchr(char *string, char ch) { // Almost like U4BE except that it takes `size` as a parameter. // The `strict` parameter defines whether we should throw in case of a length > 4. uint32_t u32_from_BE(uint8_t *in, uint8_t size, bool strict) { - uint32_t res = 0; - if (size == 1) { - res = in[0]; - } else if (size == 2) { - res = (in[0] << 8) | in[1]; - } else if (size == 3) { - res = (in[0] << 16) | (in[1] << 8) | in[2]; - } else if (size == 4) { - res = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; - } else if (strict && size != 0) { - PRINTF("Unexpected format\n"); - THROW(EXCEPTION); + switch (size) { + case 0: + return 0; + case 1: + return in[0]; + case 2: + return (in[0] << 8) | in[1]; + case 3: + return (in[0] << 16) | (in[1] << 8) | in[2]; + case 4: + return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; + default: + if (strict) { + PRINTF("Unexpected format\n"); + THROW(EXCEPTION); + } + return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; } - return res; } bool uint256_to_decimal(const uint8_t *value, size_t value_len, char *out, size_t out_len) { @@ -89,7 +93,7 @@ bool uint256_to_decimal(const uint8_t *value, size_t value_len, char *out, size_ // Not enough space to hold "0" and \0. return false; } - strncpy(out, "0", out_len); + strlcpy(out, "0", out_len); return true; } diff --git a/src_common/ethUstream.c b/src_common/ethUstream.c index 8d5c979..a67ec71 100644 --- a/src_common/ethUstream.c +++ b/src_common/ethUstream.c @@ -486,7 +486,6 @@ static parserStatus_e parseRLP(txContext_t *context) { } // Ready to process this field if (!rlpDecodeLength(context->rlpBuffer, - context->rlpBufferPos, &context->currentFieldLength, &offset, &context->currentFieldIsList)) { diff --git a/src_common/ethUtils.c b/src_common/ethUtils.c index 07797c4..3ad545e 100644 --- a/src_common/ethUtils.c +++ b/src_common/ethUtils.c @@ -58,11 +58,7 @@ bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid) { return true; } -bool rlpDecodeLength(uint8_t *buffer, - uint32_t bufferLength, - uint32_t *fieldLength, - uint32_t *offset, - bool *list) { +bool rlpDecodeLength(uint8_t *buffer, uint32_t *fieldLength, uint32_t *offset, bool *list) { if (*buffer <= 0x7f) { *offset = 0; *fieldLength = 1; @@ -128,7 +124,7 @@ void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, cx_sha3 } void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, - uint8_t *out, + char *out, cx_sha3_t *sha3Context, chain_config_t *chain_config) { uint8_t hashAddress[INT256_LENGTH]; @@ -138,7 +134,7 @@ void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, } void getEthAddressStringFromBinary(uint8_t *address, - uint8_t *out, + char *out, cx_sha3_t *sha3Context, chain_config_t *chain_config) { // save some precious stack space diff --git a/src_common/ethUtils.h b/src_common/ethUtils.h index 0c7a242..67712a7 100644 --- a/src_common/ethUtils.h +++ b/src_common/ethUtils.h @@ -26,7 +26,6 @@ * @brief Decode an RLP encoded field - see * https://github.com/ethereum/wiki/wiki/RLP * @param [in] buffer buffer containing the RLP encoded field to decode - * @param [in] bufferLength size of the buffer * @param [out] fieldLength length of the RLP encoded field * @param [out] offset offset to the beginning of the RLP encoded field from the * buffer @@ -34,23 +33,19 @@ * string * @return true if the RLP header is consistent */ -bool rlpDecodeLength(uint8_t *buffer, - uint32_t bufferLength, - uint32_t *fieldLength, - uint32_t *offset, - bool *list); +bool rlpDecodeLength(uint8_t *buffer, uint32_t *fieldLength, uint32_t *offset, bool *list); bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid); void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, cx_sha3_t *sha3Context); void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, - uint8_t *out, + char *out, cx_sha3_t *sha3Context, chain_config_t *chain_config); void getEthAddressStringFromBinary(uint8_t *address, - uint8_t *out, + char *out, cx_sha3_t *sha3Context, chain_config_t *chain_config); diff --git a/src_common/network.c b/src_common/network.c new file mode 100644 index 0000000..5f33b8a --- /dev/null +++ b/src_common/network.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include "network.h" +#include "os.h" +#include "shared_context.h" +#include "utils.h" + +// Mappping of chain ids to networks. +const network_info_t NETWORK_MAPPING[] = { + {.chain_id = 1, .name = "Ethereum", .ticker = "ETH "}, + {.chain_id = 3, .name = "Ropsten", .ticker = "ETH "}, + {.chain_id = 4, .name = "Rinkeby", .ticker = "ETH "}, + {.chain_id = 5, .name = "Goerli", .ticker = "ETH "}, + {.chain_id = 10, .name = "Optimism", .ticker = "ETH "}, + {.chain_id = 42, .name = "Kovan", .ticker = "ETH "}, + {.chain_id = 56, .name = "BSC", .ticker = "BNB "}, + {.chain_id = 100, .name = "xDai", .ticker = "xDAI "}, + {.chain_id = 137, .name = "Polygon", .ticker = "MATIC "}, + {.chain_id = 250, .name = "Fantom", .ticker = "FTM "}, + {.chain_id = 43114, .name = "Avalanche", .ticker = "AVAX "}}; + +uint32_t get_chain_id(void) { + uint32_t chain_id = 0; + + switch (txContext.txType) { + case LEGACY: + chain_id = u32_from_BE(txContext.content->v, txContext.content->vLength, true); + break; + case EIP2930: + case EIP1559: + chain_id = u32_from_BE(tmpContent.txContent.chainID.value, + tmpContent.txContent.chainID.length, + true); + break; + default: + PRINTF("Txtype `%d` not supported while generating chainID\n", txContext.txType); + break; + } + PRINTF("ChainID: %d\n", chain_id); + return chain_id; +} + +network_info_t *get_network(void) { + uint32_t chain_id = get_chain_id(); + for (uint8_t i = 0; i < sizeof(NETWORK_MAPPING) / sizeof(*NETWORK_MAPPING); i++) { + if (NETWORK_MAPPING[i].chain_id == chain_id) { + return (network_info_t *) PIC(&NETWORK_MAPPING[i]); + } + } + return NULL; +} + +char *get_network_name(void) { + network_info_t *network = get_network(); + if (network == NULL) { + return NULL; + } else { + return (char *) PIC(network->name); + } +} + +char *get_network_ticker(void) { + network_info_t *network = get_network(); + if (network == NULL) { + return chainConfig->coinName; + } else { + return (char *) PIC(network->ticker); + } +} diff --git a/src_common/network.h b/src_common/network.h new file mode 100644 index 0000000..e8c4f7a --- /dev/null +++ b/src_common/network.h @@ -0,0 +1,19 @@ +#include +#include "tokens.h" + +#define NETWORK_STRING_MAX_SIZE 12 + +typedef struct network_info_s { + const char name[NETWORK_STRING_MAX_SIZE]; + const char ticker[MAX_TICKER_LEN]; + uint32_t chain_id; +} network_info_t; + +// Returns the current chain id. Defaults to 0 if txType was not found. +uint32_t get_chain_id(void); +// Returns a pointer to the network struct, or NULL if there is none. +network_info_t *get_network(void); +// Returns a pointer to the network name, or NULL if there is none. +char *get_network_name(void); +// Returns a pointer to the network ticker, or chainConfig->coinName if there is none. +char *get_network_ticker(void); \ 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 4bc4e76..ca10fc3 100644 --- a/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c +++ b/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c @@ -4,7 +4,7 @@ #include "feature_getEth2PublicKey.h" #include "ui_callbacks.h" -unsigned int io_seproxyhal_touch_eth2_address_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_eth2_address_ok(__attribute__((unused)) const bagl_element_t *e) { uint32_t tx = set_result_get_eth2_publicKey(); G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x00; diff --git a/src_features/getPublicKey/ui_common_getPublicKey.c b/src_features/getPublicKey/ui_common_getPublicKey.c index 23a0f66..c7bd3a3 100644 --- a/src_features/getPublicKey/ui_common_getPublicKey.c +++ b/src_features/getPublicKey/ui_common_getPublicKey.c @@ -2,7 +2,7 @@ #include "feature_getPublicKey.h" #include "ui_callbacks.h" -unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_address_ok(__attribute__((unused)) const bagl_element_t *e) { uint32_t tx = set_result_get_publicKey(); G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x00; @@ -14,7 +14,7 @@ unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e) { return 0; // do not redraw the widget } -unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_address_cancel(__attribute__((unused)) const bagl_element_t *e) { G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[1] = 0x85; reset_app_context(); diff --git a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c index 5f73191..94ddebc 100644 --- a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c +++ b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c @@ -88,8 +88,10 @@ void handleProvideErc20TokenInformation(uint8_t p1, 32, workBuffer + offset, dataLength)) { +#ifndef HAVE_BYPASS_SIGNATURES PRINTF("Invalid token signature\n"); THROW(0x6A80); +#endif } tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1; THROW(0x9000); @@ -102,7 +104,7 @@ void handleProvideErc20TokenInformation(uint8_t p1, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, - unsigned int *tx) { + __attribute__((unused)) unsigned int *tx) { UNUSED(p1); UNUSED(p2); UNUSED(flags); @@ -143,8 +145,8 @@ void handleProvideErc20TokenInformation(uint8_t p1, offset += 4; dataLength -= 4; chainId = U4BE(workBuffer, offset); - if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) { - PRINTF("ChainId token mismatch\n"); + if ((chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) && (chainConfig->chainId != chainId)) { + PRINTF("ChainId token mismatch: %d vs %d\n", chainConfig->chainId, chainId); THROW(0x6A80); } offset += 4; @@ -175,8 +177,10 @@ void handleProvideErc20TokenInformation(uint8_t p1, 32, workBuffer + offset, dataLength)) { +#ifndef HAVE_BYPASS_SIGNATURES PRINTF("Invalid token signature\n"); THROW(0x6A80); +#endif } } @@ -193,8 +197,10 @@ void handleProvideErc20TokenInformation(uint8_t p1, 32, workBuffer + offset, dataLength)) { +#ifndef HAVE_BYPASS_SIGNATURES PRINTF("Invalid token signature\n"); THROW(0x6A80); +#endif } #endif diff --git a/src_features/setEth2WithdrawalIndex/cmd_setEth2WithdrawalIndex.c b/src_features/setEth2WithdrawalIndex/cmd_setEth2WithdrawalIndex.c index ea99f03..d2338ef 100644 --- a/src_features/setEth2WithdrawalIndex/cmd_setEth2WithdrawalIndex.c +++ b/src_features/setEth2WithdrawalIndex/cmd_setEth2WithdrawalIndex.c @@ -7,8 +7,8 @@ void handleSetEth2WithdrawalIndex(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, - unsigned int *flags, - unsigned int *tx) { + __attribute__((unused)) unsigned int *flags, + __attribute__((unused)) unsigned int *tx) { if (dataLength != 4) { THROW(0x6700); } diff --git a/src_features/setExternalPlugin/cmd_setExternalPlugin.c b/src_features/setExternalPlugin/cmd_setExternalPlugin.c index 494915b..93c0b64 100644 --- a/src_features/setExternalPlugin/cmd_setExternalPlugin.c +++ b/src_features/setExternalPlugin/cmd_setExternalPlugin.c @@ -3,8 +3,7 @@ #include "ui_flow.h" #include "tokens.h" -#define CONTRACT_ADDR_SIZE 20 -#define SELECTOR_SIZE 4 +#define SELECTOR_SIZE 4 void handleSetExternalPlugin(uint8_t p1, uint8_t p2, @@ -19,7 +18,7 @@ void handleSetExternalPlugin(uint8_t p1, uint8_t hash[32]; cx_ecfp_public_key_t tokenKey; uint8_t pluginNameLength = *workBuffer; - const size_t payload_size = 1 + pluginNameLength + CONTRACT_ADDR_SIZE + SELECTOR_SIZE; + const size_t payload_size = 1 + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE; if (dataLength <= payload_size) { THROW(0x6A80); @@ -43,7 +42,9 @@ void handleSetExternalPlugin(uint8_t p1, workBuffer + payload_size, dataLength - payload_size)) { PRINTF("Invalid external plugin signature %.*H\n", payload_size, workBuffer); +#ifndef HAVE_BYPASS_SIGNATURES THROW(0x6A80); +#endif } // move on to the rest of the payload parsing @@ -65,8 +66,8 @@ void handleSetExternalPlugin(uint8_t p1, CATCH_OTHER(e) { PRINTF("%s external plugin is not present\n", dataContext.tokenContext.pluginName); memset(dataContext.tokenContext.pluginName, - sizeof(dataContext.tokenContext.pluginName), - 0); + 0, + sizeof(dataContext.tokenContext.pluginName)); THROW(0x6984); } FINALLY { @@ -76,8 +77,8 @@ void handleSetExternalPlugin(uint8_t p1, PRINTF("Plugin found\n"); - memmove(dataContext.tokenContext.contract_address, workBuffer, CONTRACT_ADDR_SIZE); - workBuffer += 20; + memmove(dataContext.tokenContext.contract_address, workBuffer, ADDRESS_LENGTH); + workBuffer += ADDRESS_LENGTH; memmove(dataContext.tokenContext.method_selector, workBuffer, SELECTOR_SIZE); externalPluginIsSet = true; diff --git a/src_features/signMessage/cmd_signMessage.c b/src_features/signMessage/cmd_signMessage.c index 3703b28..2c5ec6f 100644 --- a/src_features/signMessage/cmd_signMessage.c +++ b/src_features/signMessage/cmd_signMessage.c @@ -3,7 +3,7 @@ #include "utils.h" #include "ui_flow.h" -static const char const SIGN_MAGIC[] = +static const char SIGN_MAGIC[] = "\x19" "Ethereum Signed Message:\n"; diff --git a/src_features/signMessage/ui_common_signMessage.c b/src_features/signMessage/ui_common_signMessage.c index 3e53a26..02b15c3 100644 --- a/src_features/signMessage/ui_common_signMessage.c +++ b/src_features/signMessage/ui_common_signMessage.c @@ -1,10 +1,9 @@ #include "shared_context.h" #include "ui_callbacks.h" -unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_signMessage_ok(__attribute__((unused)) const bagl_element_t *e) { uint8_t privateKeyData[INT256_LENGTH]; uint8_t signature[100]; - uint8_t signatureLength; cx_ecfp_private_key_t privateKey; uint32_t tx = 0; io_seproxyhal_io_heartbeat(); @@ -18,14 +17,14 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) { explicit_bzero(privateKeyData, sizeof(privateKeyData)); unsigned int info = 0; io_seproxyhal_io_heartbeat(); - signatureLength = cx_ecdsa_sign(&privateKey, - CX_RND_RFC6979 | CX_LAST, - CX_SHA256, - tmpCtx.messageSigningContext.hash, - sizeof(tmpCtx.messageSigningContext.hash), - signature, - sizeof(signature), - &info); + cx_ecdsa_sign(&privateKey, + CX_RND_RFC6979 | CX_LAST, + CX_SHA256, + tmpCtx.messageSigningContext.hash, + sizeof(tmpCtx.messageSigningContext.hash), + signature, + sizeof(signature), + &info); explicit_bzero(&privateKey, sizeof(privateKey)); G_io_apdu_buffer[0] = 27; if (info & CX_ECCINFO_PARITY_ODD) { @@ -46,7 +45,8 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) { return 0; // do not redraw the widget } -unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_signMessage_cancel(__attribute__((unused)) + const bagl_element_t *e) { reset_app_context(); G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[1] = 0x85; diff --git a/src_features/signMessageEIP712/ui_common_signMessage712.c b/src_features/signMessageEIP712/ui_common_signMessage712.c index 1abdfc3..db97137 100644 --- a/src_features/signMessageEIP712/ui_common_signMessage712.c +++ b/src_features/signMessageEIP712/ui_common_signMessage712.c @@ -1,13 +1,13 @@ #include "shared_context.h" #include "ui_callbacks.h" -static const uint8_t const EIP_712_MAGIC[] = {0x19, 0x01}; +static const uint8_t EIP_712_MAGIC[] = {0x19, 0x01}; -unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_signMessage712_v0_ok(__attribute__((unused)) + const bagl_element_t *e) { uint8_t privateKeyData[INT256_LENGTH]; uint8_t hash[INT256_LENGTH]; uint8_t signature[100]; - uint8_t signatureLength; cx_ecfp_private_key_t privateKey; uint32_t tx = 0; io_seproxyhal_io_heartbeat(); @@ -42,14 +42,14 @@ unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) { explicit_bzero(privateKeyData, sizeof(privateKeyData)); unsigned int info = 0; io_seproxyhal_io_heartbeat(); - signatureLength = cx_ecdsa_sign(&privateKey, - CX_RND_RFC6979 | CX_LAST, - CX_SHA256, - hash, - sizeof(hash), - signature, - sizeof(signature), - &info); + cx_ecdsa_sign(&privateKey, + CX_RND_RFC6979 | CX_LAST, + CX_SHA256, + hash, + sizeof(hash), + signature, + sizeof(signature), + &info); explicit_bzero(&privateKey, sizeof(privateKey)); G_io_apdu_buffer[0] = 27; if (info & CX_ECCINFO_PARITY_ODD) { @@ -70,7 +70,8 @@ unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) { return 0; // do not redraw the widget } -unsigned int io_seproxyhal_touch_signMessage712_v0_cancel(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_signMessage712_v0_cancel(__attribute__((unused)) + const bagl_element_t *e) { reset_app_context(); G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[1] = 0x85; diff --git a/src_features/signTx/feature_signTx.h b/src_features/signTx/feature_signTx.h index ff9be11..24400da 100644 --- a/src_features/signTx/feature_signTx.h +++ b/src_features/signTx/feature_signTx.h @@ -10,5 +10,5 @@ typedef enum { customStatus_e customProcessor(txContext_t *context); void finalizeParsing(bool direct); void prepareFeeDisplay(); -void prepareChainIdDisplay(); +void prepareNetworkDisplay(); void ux_approve_tx(bool fromPlugin); diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c index 45eb058..a7cb59e 100644 --- a/src_features/signTx/logic_signTx.c +++ b/src_features/signTx/logic_signTx.c @@ -2,10 +2,12 @@ #include "utils.h" #include "ui_callbacks.h" #include "ui_flow.h" +#include "feature_signTx.h" #ifdef HAVE_STARKWARE #include "stark_utils.h" #endif #include "eth_plugin_handler.h" +#include "network.h" #define ERR_SILENT_MODE_CHECK_FAILED 0x6001 @@ -170,7 +172,7 @@ void to_uppercase(char *str, unsigned char size) { } } -void compareOrCopy(char *preapproved_string, char *parsed_string, bool silent_mode) { +void compareOrCopy(char *preapproved_string, size_t size, char *parsed_string, bool silent_mode) { if (silent_mode) { /* ETH address are not fundamentally case sensitive but might have some for checksum purpose, so let's get rid of these diffs */ @@ -180,7 +182,7 @@ void compareOrCopy(char *preapproved_string, char *parsed_string, bool silent_mo THROW(ERR_SILENT_MODE_CHECK_FAILED); } } else { - strcpy(preapproved_string, parsed_string); + strlcpy(preapproved_string, parsed_string, size); } } @@ -208,7 +210,7 @@ static void computeFees(txInt256_t *BEgasPrice, txInt256_t *BEgasLimit, uint256_ } static void feesToString(uint256_t *rawFee, char *displayBuffer, uint32_t displayBufferSize) { - uint8_t *feeTicker = (uint8_t *) PIC(chainConfig->coinName); + char *feeTicker = get_network_ticker(); uint8_t tickerOffset = 0; uint32_t i; @@ -271,38 +273,58 @@ uint32_t get_chainID() { return chain_id; } -void prepareChainIdDisplay() { - uint32_t chainID = get_chainID(); - uint8_t res = snprintf(strings.common.chainID, sizeof(strings.common.chainID), "%d", chainID); - if (res >= sizeof(strings.common.chainID)) { - // If the return value is higher or equal to the size passed in as parameter, then - // the output was truncated. Return the appropriate error code. - THROW(0x6502); +void prepareNetworkDisplay() { + char *name = get_network_name(); + if (name == NULL) { + // No network name found so simply copy the chain ID as the network name. + uint32_t chain_id = get_chain_id(); + uint8_t res = snprintf(strings.common.network_name, + sizeof(strings.common.network_name), + "%d", + chain_id); + if (res >= sizeof(strings.common.network_name)) { + // If the return value is higher or equal to the size passed in as parameter, then + // the output was truncated. Return the appropriate error code. + THROW(0x6502); + } + } else { + // Network name found, simply copy it. + strlcpy(strings.common.network_name, name, sizeof(strings.common.network_name)); } } +static void get_public_key(uint8_t *out, uint8_t outLength) { + uint8_t privateKeyData[INT256_LENGTH] = {0}; + cx_ecfp_private_key_t privateKey = {0}; + cx_ecfp_public_key_t publicKey = {0}; + + if (outLength < ADDRESS_LENGTH) { + return; + } + + os_perso_derive_node_bip32(CX_CURVE_256K1, + tmpCtx.transactionContext.bip32Path, + tmpCtx.transactionContext.pathLength, + privateKeyData, + NULL); + cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey); + cx_ecfp_generate_pair(CX_CURVE_256K1, &publicKey, &privateKey, 1); + explicit_bzero(&privateKey, sizeof(privateKey)); + explicit_bzero(privateKeyData, sizeof(privateKeyData)); + getEthAddressFromKey(&publicKey, out, &global_sha3); +} + void finalizeParsing(bool direct) { char displayBuffer[50]; uint8_t decimals = WEI_TO_ETHER; - uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName); + char *ticker = get_network_ticker(); ethPluginFinalize_t pluginFinalize; - tokenDefinition_t *token1 = NULL, *token2 = NULL; bool genericUI = true; // Verify the chain - if (chainConfig->chainId != 0) { - uint32_t id = 0; - - if (txContext.txType == LEGACY) { - id = u32_from_BE(txContext.content->v, txContext.content->vLength, true); - } else if (txContext.txType == EIP2930 || txContext.txType == EIP1559) { - id = u32_from_BE(txContext.content->chainID.value, - txContext.content->chainID.length, - false); - } else { - PRINTF("TxType `%u` not supported while checking for chainID\n", txContext.txType); - return; - } + if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) { + // TODO: Could we remove above check? + uint32_t id = get_chain_id(); if (chainConfig->chainId != id) { PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId); @@ -325,6 +347,11 @@ void finalizeParsing(bool direct) { if (dataContext.tokenContext.pluginStatus >= ETH_PLUGIN_RESULT_SUCCESSFUL) { genericUI = false; eth_plugin_prepare_finalize(&pluginFinalize); + + uint8_t msg_sender[ADDRESS_LENGTH] = {0}; + get_public_key(msg_sender, sizeof(msg_sender)); + pluginFinalize.address = msg_sender; + if (!eth_plugin_call(ETH_PLUGIN_FINALIZE, (void *) &pluginFinalize)) { PRINTF("Plugin finalize call failed\n"); reportFinalizeError(direct); @@ -334,22 +361,22 @@ void finalizeParsing(bool direct) { } // Lookup tokens if requested ethPluginProvideToken_t pluginProvideToken; + eth_plugin_prepare_provide_token(&pluginProvideToken); if ((pluginFinalize.tokenLookup1 != NULL) || (pluginFinalize.tokenLookup2 != NULL)) { if (pluginFinalize.tokenLookup1 != NULL) { PRINTF("Lookup1: %.*H\n", ADDRESS_LENGTH, pluginFinalize.tokenLookup1); - token1 = getKnownToken(pluginFinalize.tokenLookup1); - if (token1 != NULL) { - PRINTF("Token1 ticker: %s\n", token1->ticker); + pluginProvideToken.token1 = getKnownToken(pluginFinalize.tokenLookup1); + if (pluginProvideToken.token1 != NULL) { + PRINTF("Token1 ticker: %s\n", pluginProvideToken.token1->ticker); } } if (pluginFinalize.tokenLookup2 != NULL) { PRINTF("Lookup2: %.*H\n", ADDRESS_LENGTH, pluginFinalize.tokenLookup2); - token2 = getKnownToken(pluginFinalize.tokenLookup2); - if (token2 != NULL) { - PRINTF("Token2 ticker: %s\n", token2->ticker); + pluginProvideToken.token2 = getKnownToken(pluginFinalize.tokenLookup2); + if (pluginProvideToken.token2 != NULL) { + PRINTF("Token2 ticker: %s\n", pluginProvideToken.token2->ticker); } } - eth_plugin_prepare_provide_token(&pluginProvideToken, token1, token2); if (eth_plugin_call(ETH_PLUGIN_PROVIDE_TOKEN, (void *) &pluginProvideToken) <= ETH_PLUGIN_RESULT_UNSUCCESSFUL) { PRINTF("Plugin provide token call failed\n"); @@ -384,9 +411,9 @@ void finalizeParsing(bool direct) { tmpContent.txContent.value.length = 32; memmove(tmpContent.txContent.destination, pluginFinalize.address, 20); tmpContent.txContent.destinationLength = 20; - if (token1 != NULL) { - decimals = token1->decimals; - ticker = token1->ticker; + if (pluginProvideToken.token1 != NULL) { + decimals = pluginProvideToken.token1->decimals; + ticker = pluginProvideToken.token1->ticker; } break; default: @@ -407,48 +434,50 @@ void finalizeParsing(bool direct) { return; } } + // Prepare destination address to display if (genericUI) { if (tmpContent.txContent.destinationLength != 0) { displayBuffer[0] = '0'; displayBuffer[1] = 'x'; getEthAddressStringFromBinary(tmpContent.txContent.destination, - (uint8_t *) displayBuffer + 2, + displayBuffer + 2, &global_sha3, chainConfig); - compareOrCopy(strings.common.fullAddress, displayBuffer, called_from_swap); + compareOrCopy(strings.common.fullAddress, + sizeof(strings.common.fullAddress), + displayBuffer, + called_from_swap); } else { strcpy(strings.common.fullAddress, "Contract"); } } + // Prepare amount to display if (genericUI) { amountToString(tmpContent.txContent.value.value, tmpContent.txContent.value.length, decimals, - (char *) ticker, + ticker, displayBuffer, sizeof(displayBuffer)); - compareOrCopy(strings.common.fullAmount, displayBuffer, called_from_swap); - } - // Prepare nonce to display - if (genericUI) { - uint256_t nonce; - convertUint256BE(tmpContent.txContent.nonce.value, - tmpContent.txContent.nonce.length, - &nonce); - tostring256(&nonce, 10, displayBuffer, sizeof(displayBuffer)); - strncpy(strings.common.nonce, displayBuffer, sizeof(strings.common.nonce)); - } - // Compute maximum fee - if (genericUI) { - prepareFeeDisplay(); + compareOrCopy(strings.common.fullAmount, + sizeof(strings.common.fullAddress), + displayBuffer, + called_from_swap); } + // Prepare nonce to display + uint256_t nonce; + convertUint256BE(tmpContent.txContent.nonce.value, tmpContent.txContent.nonce.length, &nonce); + tostring256(&nonce, 10, displayBuffer, sizeof(displayBuffer)); + strlcpy(strings.common.nonce, displayBuffer, sizeof(strings.common.nonce)); + + // Compute maximum fee + prepareFeeDisplay(); + // Prepare chainID field - if (genericUI) { - prepareChainIdDisplay(); - } + prepareNetworkDisplay(); bool no_consent; diff --git a/src_features/signTx/ui_common_signTx.c b/src_features/signTx/ui_common_signTx.c index 55ebaa3..eb2ee11 100644 --- a/src_features/signTx/ui_common_signTx.c +++ b/src_features/signTx/ui_common_signTx.c @@ -2,10 +2,9 @@ #include "utils.h" #include "ui_callbacks.h" -unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_element_t *e) { uint8_t privateKeyData[INT256_LENGTH]; uint8_t signature[100]; - uint8_t signatureLength; cx_ecfp_private_key_t privateKey; uint32_t tx = 0; uint32_t v = u32_from_BE(tmpContent.txContent.v, tmpContent.txContent.vLength, true); @@ -19,14 +18,14 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) { explicit_bzero(privateKeyData, sizeof(privateKeyData)); unsigned int info = 0; io_seproxyhal_io_heartbeat(); - signatureLength = cx_ecdsa_sign(&privateKey, - CX_RND_RFC6979 | CX_LAST, - CX_SHA256, - tmpCtx.transactionContext.hash, - sizeof(tmpCtx.transactionContext.hash), - signature, - sizeof(signature), - &info); + cx_ecdsa_sign(&privateKey, + CX_RND_RFC6979 | CX_LAST, + CX_SHA256, + tmpCtx.transactionContext.hash, + sizeof(tmpCtx.transactionContext.hash), + signature, + sizeof(signature), + &info); explicit_bzero(&privateKey, sizeof(privateKey)); if (txContext.txType == EIP1559 || txContext.txType == EIP2930) { if (info & CX_ECCINFO_PARITY_ODD) { @@ -66,7 +65,7 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) { return 0; // do not redraw the widget } -unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_tx_cancel(__attribute__((unused)) const bagl_element_t *e) { reset_app_context(); G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[1] = 0x85; @@ -77,7 +76,7 @@ unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) { return 0; // do not redraw the widget } -unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_data_ok(__attribute__((unused)) const bagl_element_t *e) { parserStatus_e txResult = USTREAM_FINISHED; txResult = continueTx(&txContext); switch (txResult) { @@ -108,7 +107,7 @@ unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) { return 0; } -unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_data_cancel(__attribute__((unused)) const bagl_element_t *e) { reset_app_context(); io_seproxyhal_send_status(0x6985); // Display back the original UX diff --git a/src_features/signTx/ui_flow_signTx.c b/src_features/signTx/ui_flow_signTx.c index f6992f6..6b91f80 100644 --- a/src_features/signTx/ui_flow_signTx.c +++ b/src_features/signTx/ui_flow_signTx.c @@ -3,80 +3,9 @@ #include "chainConfig.h" #include "utils.h" #include "feature_signTx.h" +#include "network.h" #include "eth_plugin_handler.h" -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) { - dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE; - dataContext.tokenContext.pluginUiCurrentItem = 0; - plugin_ui_get_item(); - ux_flow_next(); - } else { - if (dataContext.tokenContext.pluginUiCurrentItem > 0) { - dataContext.tokenContext.pluginUiCurrentItem--; - plugin_ui_get_item(); - ux_flow_next(); - } else { - dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE; - dataContext.tokenContext.pluginUiCurrentItem = 0; - ux_flow_prev(); - } - } - } else { - if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) { - dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE; - plugin_ui_get_item(); - ux_flow_prev(); - } else { - if (dataContext.tokenContext.pluginUiCurrentItem < - dataContext.tokenContext.pluginUiMaxItems - 1) { - dataContext.tokenContext.pluginUiCurrentItem++; - plugin_ui_get_item(); - ux_flow_prev(); - // Reset multi page layout to the first page - G_ux.layout_paging.current = 0; -#ifdef TARGET_NANOS - ux_layout_paging_redisplay_by_addr(G_ux.stack_count - 1); -#else - ux_layout_bnnn_paging_redisplay(0); -#endif - } else { - dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE; - ux_flow_next(); - } - } - } -} - // clang-format off UX_STEP_NOCB( ux_confirm_selector_flow_1_step, @@ -224,11 +153,11 @@ UX_STEP_NOCB( .text = strings.common.maxFee, }); UX_STEP_NOCB( - ux_approval_chainid_step, + ux_approval_network_step, bnnn_paging, { - .title = "Chain ID", - .text = strings.common.chainID, + .title = "Network", + .text = strings.common.network_name, }); UX_STEP_CB( @@ -277,15 +206,13 @@ void ux_approve_tx(bool fromPlugin) { } if (fromPlugin) { - // If we're coming from a plugin then we need to prepare the display. - prepareChainIdDisplay(); - prepareFeeDisplay(); - + // Add the special dynamic display logic ux_approval_tx_flow[step++] = &ux_plugin_approval_id_step; ux_approval_tx_flow[step++] = &ux_plugin_approval_before_step; ux_approval_tx_flow[step++] = &ux_plugin_approval_display_step; ux_approval_tx_flow[step++] = &ux_plugin_approval_after_step; } else { + // We're in a regular transaction, just show the amount and the address ux_approval_tx_flow[step++] = &ux_approval_amount_step; ux_approval_tx_flow[step++] = &ux_approval_address_step; } @@ -294,19 +221,12 @@ void ux_approve_tx(bool fromPlugin) { ux_approval_tx_flow[step++] = &ux_approval_nonce_step; } - uint32_t id; - if (txContext.txType == LEGACY) { - id = u32_from_BE(txContext.content->v, txContext.content->vLength, true); - } else if (txContext.txType == EIP2930 || txContext.txType == EIP1559) { - id = - u32_from_BE(txContext.content->chainID.value, txContext.content->chainID.length, false); - } else { - PRINTF("TxType `%u` not supported while preparing to approve tx\n", txContext.txType); - THROW(0x6501); - } - if (id != ETHEREUM_MAINNET_CHAINID) { - ux_approval_tx_flow[step++] = &ux_approval_chainid_step; + uint32_t chain_id = get_chain_id(); + if (chainConfig->chainId == ETHEREUM_MAINNET_CHAINID && chain_id != chainConfig->chainId) { + // TODO: do we need the `&&` above? + ux_approval_tx_flow[step++] = &ux_approval_network_step; } + ux_approval_tx_flow[step++] = &ux_approval_fees_step; ux_approval_tx_flow[step++] = &ux_approval_accept_step; ux_approval_tx_flow[step++] = &ux_approval_reject_step; diff --git a/src_features/signTx/ui_plugin.c b/src_features/signTx/ui_plugin.c new file mode 100644 index 0000000..9ebaa24 --- /dev/null +++ b/src_features/signTx/ui_plugin.c @@ -0,0 +1,82 @@ +#include "feature_signTx.h" +#include "ux.h" +#include "eth_plugin_handler.h" +#include "ui_callbacks.h" +#include "ui_plugin.h" + +#ifdef TARGET_NANOS +// This function is not exported by the SDK +void ux_layout_paging_redisplay_by_addr(unsigned int stack_slot); +#endif + +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) { + dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE; + dataContext.tokenContext.pluginUiCurrentItem = 0; + plugin_ui_get_item(); + ux_flow_next(); + } else { + if (dataContext.tokenContext.pluginUiCurrentItem > 0) { + dataContext.tokenContext.pluginUiCurrentItem--; + plugin_ui_get_item(); + ux_flow_next(); + } else { + dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE; + dataContext.tokenContext.pluginUiCurrentItem = 0; + ux_flow_prev(); + } + } + } else { + if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) { + dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE; + plugin_ui_get_item(); + ux_flow_prev(); + } else { + if (dataContext.tokenContext.pluginUiCurrentItem < + dataContext.tokenContext.pluginUiMaxItems - 1) { + dataContext.tokenContext.pluginUiCurrentItem++; + plugin_ui_get_item(); + ux_flow_prev(); + // Reset multi page layout to the first page + G_ux.layout_paging.current = 0; +#ifdef TARGET_NANOS + ux_layout_paging_redisplay_by_addr(G_ux.stack_count - 1); +#else + ux_layout_bnnn_paging_redisplay(0); +#endif + } else { + dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE; + ux_flow_next(); + } + } + } +} \ No newline at end of file diff --git a/src_features/signTx/ui_plugin.h b/src_features/signTx/ui_plugin.h new file mode 100644 index 0000000..28179b2 --- /dev/null +++ b/src_features/signTx/ui_plugin.h @@ -0,0 +1,5 @@ +#pragma once + +void plugin_ui_get_id(); +void plugin_ui_get_item(); +void display_next_plugin_item(bool entering); \ No newline at end of file diff --git a/src_features/stark_getPublicKey/ui_common_stark_getPublicKey.c b/src_features/stark_getPublicKey/ui_common_stark_getPublicKey.c index db03c53..94a6658 100644 --- a/src_features/stark_getPublicKey/ui_common_stark_getPublicKey.c +++ b/src_features/stark_getPublicKey/ui_common_stark_getPublicKey.c @@ -4,7 +4,7 @@ #include "ui_callbacks.h" #include "feature_stark_getPublicKey.h" -unsigned int io_seproxyhal_touch_stark_pubkey_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_stark_pubkey_ok(__attribute__((unused)) const bagl_element_t *e) { uint32_t tx = set_result_get_stark_publicKey(); G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x00; diff --git a/src_features/stark_provideQuantum/cmd_stark_provideQuantum.c b/src_features/stark_provideQuantum/cmd_stark_provideQuantum.c index 6433e33..15f6d16 100644 --- a/src_features/stark_provideQuantum/cmd_stark_provideQuantum.c +++ b/src_features/stark_provideQuantum/cmd_stark_provideQuantum.c @@ -5,11 +5,11 @@ #include "ui_flow.h" void handleStarkwareProvideQuantum(uint8_t p1, - uint8_t p2, + __attribute__((unused)) uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, - unsigned int *flags, - unsigned int *tx) { + __attribute__((unused)) unsigned int *flags, + __attribute__((unused)) unsigned int *tx) { size_t i = 0; uint8_t expectedDataSize = 20 + 32; uint8_t addressZero = 0; diff --git a/src_features/stark_sign/cmd_stark_sign.c b/src_features/stark_sign/cmd_stark_sign.c index 2420f48..9329838 100644 --- a/src_features/stark_sign/cmd_stark_sign.c +++ b/src_features/stark_sign/cmd_stark_sign.c @@ -16,7 +16,7 @@ void handleStarkwareSignMessage(uint8_t p1, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, - unsigned int *tx) { + __attribute__((unused)) unsigned int *tx) { uint8_t privateKeyData[INT256_LENGTH]; uint32_t i; uint8_t bip32PathLength = *(dataBuffer); diff --git a/src_features/stark_sign/ui_common_stark_sign.c b/src_features/stark_sign/ui_common_stark_sign.c index 9443f72..b5feede 100644 --- a/src_features/stark_sign/ui_common_stark_sign.c +++ b/src_features/stark_sign/ui_common_stark_sign.c @@ -4,7 +4,7 @@ #include "stark_utils.h" #include "ui_callbacks.h" -unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_stark_ok(__attribute__((unused)) const bagl_element_t *e) { uint8_t privateKeyData[32]; uint8_t signature[72]; uint32_t tx = 0; diff --git a/src_features/stark_sign/ui_flow_stark_sign.c b/src_features/stark_sign/ui_flow_stark_sign.c index c1df89d..6f1b247 100644 --- a/src_features/stark_sign/ui_flow_stark_sign.c +++ b/src_features/stark_sign/ui_flow_stark_sign.c @@ -17,7 +17,7 @@ void stark_sign_display_condition_address() { strings.tmp.tmp[0] = '0'; strings.tmp.tmp[1] = 'x'; getEthAddressStringFromBinary(dataContext.starkContext.conditionAddress, - (uint8_t *) (strings.tmp.tmp + 2), + strings.tmp.tmp + 2, &global_sha3, chainConfig); strings.tmp.tmp[42] = '\0'; diff --git a/src_features/stark_unsafe_sign/cmd_stark_unsafe_sign.c b/src_features/stark_unsafe_sign/cmd_stark_unsafe_sign.c index 0f3e10c..e899816 100644 --- a/src_features/stark_unsafe_sign/cmd_stark_unsafe_sign.c +++ b/src_features/stark_unsafe_sign/cmd_stark_unsafe_sign.c @@ -11,7 +11,7 @@ void handleStarkwareUnsafeSign(uint8_t p1, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, - unsigned int *tx) { + __attribute__((unused)) unsigned int *tx) { uint32_t i; uint8_t privateKeyData[INT256_LENGTH]; cx_ecfp_public_key_t publicKey; 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 fcd7375..2a75200 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 @@ -4,7 +4,8 @@ #include "stark_utils.h" #include "ui_callbacks.h" -unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(__attribute__((unused)) + const bagl_element_t *e) { cx_ecfp_private_key_t privateKey; uint8_t privateKeyData[INT256_LENGTH]; uint8_t signature[72]; diff --git a/src_plugins/compound/compound_plugin.c b/src_plugins/compound/compound_plugin.c index 5a0742d..66437a8 100644 --- a/src_plugins/compound/compound_plugin.c +++ b/src_plugins/compound/compound_plugin.c @@ -30,7 +30,7 @@ static const uint8_t COMPOUND_EXPECTED_DATA_SIZE[] = { typedef struct compound_parameters_t { uint8_t selectorIndex; uint8_t amount[32]; - uint8_t ticker_1[MAX_TICKER_LEN]; + char ticker_1[MAX_TICKER_LEN]; uint8_t decimals; } compound_parameters_t; @@ -43,7 +43,7 @@ typedef struct underlying_asset_decimals_t { 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 const UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_BINDINGS] = { +const underlying_asset_decimals_t UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_BINDINGS] = { {"cDAI", 18}, {"CETH", 18}, {"CUSDC", 6}, @@ -153,15 +153,15 @@ void compound_plugin_call(int message, void *parameters) { compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext; PRINTF("compound plugin provide token: %d\n", (msg->token1 != NULL)); if (msg->token1 != NULL) { - strcpy((char *) context->ticker_1, (char *) msg->token1->ticker); + strlcpy(context->ticker_1, msg->token1->ticker, MAX_TICKER_LEN); switch (context->selectorIndex) { case COMPOUND_REDEEM_UNDERLYING: case COMPOUND_MINT: case CETH_MINT: - msg->result = get_underlying_asset_decimals((char *) &context->ticker_1, - &context->decimals) - ? ETH_PLUGIN_RESULT_OK - : ETH_PLUGIN_RESULT_FALLBACK; + 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 @@ -182,22 +182,22 @@ void compound_plugin_call(int message, void *parameters) { case ETH_PLUGIN_QUERY_CONTRACT_ID: { ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters; compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext; - strcpy(msg->name, "Type"); + strlcpy(msg->name, "Type", msg->nameLength); switch (context->selectorIndex) { case COMPOUND_REDEEM_UNDERLYING: case COMPOUND_REDEEM: - strcpy(msg->version, "Redeem"); + strlcpy(msg->version, "Redeem", msg->versionLength); break; case COMPOUND_MINT: case CETH_MINT: - strcpy(msg->version, "Lend"); + strlcpy(msg->version, "Lend", msg->versionLength); break; default: break; } - strcat(msg->version, " Assets"); + strlcat(msg->version, " Assets", msg->versionLength); msg->result = ETH_PLUGIN_RESULT_OK; } break; @@ -206,8 +206,8 @@ void compound_plugin_call(int message, void *parameters) { compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext; switch (msg->screenIndex) { case 0: { - strcpy(msg->title, "Amount"); - char *ticker_ptr = (char *) context->ticker_1; + 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) { @@ -223,11 +223,11 @@ void compound_plugin_call(int message, void *parameters) { } break; case 1: - strcpy(msg->title, "Contract"); - strcpy(msg->msg, "Compound "); - strcat(msg->msg, - (char *) context->ticker_1 + - 1); // remove the 'c' char at beginning of compound ticker + 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: diff --git a/src_plugins/erc20/erc20_plugin.c b/src_plugins/erc20/erc20_plugin.c index 99d8332..156ca07 100644 --- a/src_plugins/erc20/erc20_plugin.c +++ b/src_plugins/erc20/erc20_plugin.c @@ -16,10 +16,10 @@ typedef struct erc20_parameters_t { uint8_t selectorIndex; uint8_t destinationAddress[21]; uint8_t amount[INT256_LENGTH]; - uint8_t ticker[MAX_TICKER_LEN]; + char ticker[MAX_TICKER_LEN]; uint8_t decimals; uint8_t target; - uint8_t contract_name[MAX_CONTRACT_NAME_LEN]; + char contract_name[MAX_CONTRACT_NAME_LEN]; } erc20_parameters_t; typedef struct contract_t { @@ -27,8 +27,8 @@ typedef struct contract_t { uint8_t address[ADDRESS_LENGTH]; } contract_t; -#define NUM_CONTRACTS 11 -const contract_t const CONTRACTS[NUM_CONTRACTS] = { +#define NUM_CONTRACTS 13 +const contract_t CONTRACTS[NUM_CONTRACTS] = { // Compound {"Compound DAI", {0x5d, 0x3a, 0x53, 0x6e, 0x4d, 0x6d, 0xbd, 0x61, 0x14, 0xcc, 0x1e, 0xad, 0x35, 0x77, 0x7b, 0xab, 0x94, 0x8e, 0x36, 0x43}}, @@ -52,15 +52,21 @@ const contract_t const CONTRACTS[NUM_CONTRACTS] = { 0x48, 0x73, 0xd0, 0x0f, 0xf8, 0x5b, 0xcc, 0xde, 0xd5, 0x50}}, // Paraswap {"Paraswap", {0x1b, 0xd4, 0x35, 0xf3, 0xc0, 0x54, 0xb6, 0xe9, 0x01, 0xb7, - 0xb1, 0x08, 0xa0, 0xab, 0x76, 0x17, 0xc8, 0x08, 0x67, 0x7b}}}; + 0xb1, 0x08, 0xa0, 0xab, 0x76, 0x17, 0xc8, 0x08, 0x67, 0x7b}}, + + // stETH + {"Lido", {0x7f, 0x39, 0xc5, 0x81, 0xf5, 0x95, 0xb5, 0x3c, 0x5c, 0xb1, + 0x9b, 0xd0, 0xb3, 0xf8, 0xda, 0x6c, 0x93, 0x5e, 0x2c, 0xa0}}, + + // wstETH + {"Wrapped stETH", {0xae, 0x7a, 0xb9, 0x65, 0x20, 0xde, 0x3a, 0x18, 0xe5, 0xe1, + 0x11, 0xb5, 0xea, 0xab, 0x09, 0x53, 0x12, 0xd7, 0xfe, 0x84}}}; bool check_contract(erc20_parameters_t *context) { for (size_t i = 0; i < NUM_CONTRACTS; i++) { contract_t *contract = (contract_t *) PIC(&CONTRACTS[i]); if (memcmp(contract->address, context->destinationAddress, ADDRESS_LENGTH) == 0) { - strncpy((char *) context->contract_name, - contract->name, - sizeof(context->contract_name)); + strlcpy(context->contract_name, contract->name, sizeof(context->contract_name)); return true; } } @@ -161,7 +167,7 @@ void erc20_plugin_call(int message, void *parameters) { (msg->token2 != NULL)); if (msg->token1 != NULL) { context->target = TARGET_ADDRESS; - strcpy((char *) context->ticker, (char *) msg->token1->ticker); + strlcpy(context->ticker, msg->token1->ticker, MAX_TICKER_LEN); context->decimals = msg->token1->decimals; if (context->selectorIndex == ERC20_APPROVE) { if (check_contract(context)) { @@ -176,8 +182,8 @@ void erc20_plugin_call(int message, void *parameters) { case ETH_PLUGIN_QUERY_CONTRACT_ID: { ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters; - strcpy(msg->name, "Type"); - strcpy(msg->version, "Approve"); + strlcpy(msg->name, "Type", msg->nameLength); + strlcpy(msg->version, "Approve", msg->versionLength); msg->result = ETH_PLUGIN_RESULT_OK; } break; @@ -186,15 +192,15 @@ void erc20_plugin_call(int message, void *parameters) { erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext; switch (msg->screenIndex) { case 0: - strcpy(msg->title, "Amount"); + strlcpy(msg->title, "Amount", msg->titleLength); if (ismaxint(context->amount, sizeof(context->amount))) { - strcpy(msg->msg, "Unlimited "); - strcat(msg->msg, (char *) context->ticker); + strlcpy(msg->msg, "Unlimited ", msg->msgLength); + strlcat(msg->msg, context->ticker, msg->msgLength); } else { amountToString(context->amount, sizeof(context->amount), context->decimals, - (char *) context->ticker, + context->ticker, msg->msg, 100); } @@ -202,14 +208,14 @@ void erc20_plugin_call(int message, void *parameters) { break; case 1: if (context->target >= TARGET_CONTRACT) { - strcpy(msg->title, "Contract"); - strcpy(msg->msg, (char *) context->contract_name); + strlcpy(msg->title, "Contract", msg->titleLength); + strlcpy(msg->msg, context->contract_name, msg->msgLength); } else { - strcpy(msg->title, "Address"); + strlcpy(msg->title, "Address", msg->titleLength); msg->msg[0] = '0'; msg->msg[1] = 'x'; getEthAddressStringFromBinary(context->destinationAddress, - (uint8_t *) msg->msg + 2, + msg->msg + 2, msg->pluginSharedRW->sha3, chainConfig); } diff --git a/src_plugins/erc721/erc721_plugin.c b/src_plugins/erc721/erc721_plugin.c index 49994ce..584ac5c 100644 --- a/src_plugins/erc721/erc721_plugin.c +++ b/src_plugins/erc721/erc721_plugin.c @@ -108,8 +108,8 @@ void erc721_plugin_call(int message, void *parameters) { case ETH_PLUGIN_QUERY_CONTRACT_ID: { ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters; - strcpy(msg->name, "Allowance"); - strcpy(msg->version, ""); + strlcpy(msg->name, "Allowance", msg->nameLength); + strlcpy(msg->version, "", msg->versionLength); msg->result = ETH_PLUGIN_RESULT_OK; } break; @@ -118,19 +118,19 @@ void erc721_plugin_call(int message, void *parameters) { erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext; switch (msg->screenIndex) { case 0: - strcpy(msg->title, "Contract Name"); + strlcpy(msg->title, "Contract Name", msg->titleLength); starkware_print_eth_address(tmpContent.txContent.destination, msg->msg); msg->result = ETH_PLUGIN_RESULT_OK; break; case 1: - strcpy(msg->title, "NFT Contract"); + strlcpy(msg->title, "NFT Contract", msg->titleLength); starkware_print_eth_address(context->address, msg->msg); msg->result = ETH_PLUGIN_RESULT_OK; break; case 2: - strcpy(msg->title, "TokenID"); + strlcpy(msg->title, "TokenID", msg->titleLength); starkware_print_stark_key(context->tokenId, msg->msg); msg->result = ETH_PLUGIN_RESULT_OK; break; diff --git a/src_plugins/eth2/eth2_plugin.c b/src_plugins/eth2/eth2_plugin.c index 6687902..7a43eaf 100644 --- a/src_plugins/eth2/eth2_plugin.c +++ b/src_plugins/eth2/eth2_plugin.c @@ -32,21 +32,13 @@ typedef struct eth2_deposit_parameters_t { char deposit_address[ETH2_DEPOSIT_PUBKEY_LENGTH]; } eth2_deposit_parameters_t; -static void to_lowercase(char *str, unsigned char size) { - for (unsigned char i = 0; i < size && str[i] != 0; i++) { - if (str[i] >= 'A' && str[i] <= 'Z') { - str[i] += 'a' - 'A'; - } - } -} - // Fills the `out` buffer with the lowercase string representation of the pubkey passed in as binary // format by `in`. Does not check the size, so expects `out` to be big enough to hold the string // representation. Returns the length of string (counting the null terminating character). static int getEthDisplayableAddress(char *out, uint8_t *in, cx_sha3_t *sha3) { out[0] = '0'; out[1] = 'x'; - getEthAddressStringFromBinary(in, (uint8_t *) out + 2, sha3, chainConfig); + getEthAddressStringFromBinary(in, out + 2, sha3, chainConfig); uint8_t destinationLen = strlen(out) + 1; // Adding one to account for \0. @@ -143,7 +135,7 @@ void eth2_plugin_call(int message, void *parameters) { msg->pluginSharedRW->sha3); // Copy back the string to the global variable. - strcpy(context->deposit_address, tmp); + strlcpy(context->deposit_address, tmp, ETH2_DEPOSIT_PUBKEY_LENGTH); msg->result = ETH_PLUGIN_RESULT_OK; break; } @@ -206,8 +198,8 @@ void eth2_plugin_call(int message, void *parameters) { case ETH_PLUGIN_QUERY_CONTRACT_ID: { ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters; - strcpy(msg->name, "ETH2"); - strcpy(msg->version, "Deposit"); + strlcpy(msg->name, "ETH2", msg->nameLength); + strlcpy(msg->version, "Deposit", msg->versionLength); msg->result = ETH_PLUGIN_RESULT_OK; } break; @@ -217,19 +209,19 @@ void eth2_plugin_call(int message, void *parameters) { switch (msg->screenIndex) { case 0: { // Amount screen uint8_t decimals = WEI_TO_ETHER; - uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName); - strcpy(msg->title, "Amount"); + char *ticker = chainConfig->coinName; + strlcpy(msg->title, "Amount", msg->titleLength); amountToString(tmpContent.txContent.value.value, tmpContent.txContent.value.length, decimals, - (char *) ticker, + ticker, msg->msg, 100); msg->result = ETH_PLUGIN_RESULT_OK; } break; case 1: { // Deposit pubkey screen - strcpy(msg->title, "Validator"); - strcpy(msg->msg, context->deposit_address); + strlcpy(msg->title, "Validator", msg->titleLength); + strlcpy(msg->msg, context->deposit_address, msg->msgLength); msg->result = ETH_PLUGIN_RESULT_OK; } default: diff --git a/src_plugins/starkware/starkware_plugin.c b/src_plugins/starkware/starkware_plugin.c index cb4d584..c2ae91e 100644 --- a/src_plugins/starkware/starkware_plugin.c +++ b/src_plugins/starkware/starkware_plugin.c @@ -280,21 +280,25 @@ void starkware_print_stark_key(uint8_t *starkKey, char *destination) { } // TODO : rewrite as independant code -void starkware_print_eth_address(uint8_t *address, char *destination) { +void starkware_print_eth_address(uint8_t *address, char *destination, size_t destinationLength) { + if (destinationLength < 43) { + strlcpy(destination, "ERROR", destinationLength); + return; + } destination[0] = '0'; destination[1] = 'x'; - getEthAddressStringFromBinary(address, - (uint8_t *) (destination + 2), - &global_sha3, - chainConfig); + getEthAddressStringFromBinary(address, destination + 2, &global_sha3, chainConfig); destination[42] = '\0'; } // TODO : rewrite as independant code -void starkware_print_amount(uint8_t *amountData, char *destination, bool forEscape) { +void starkware_print_amount(uint8_t *amountData, + char *destination, + size_t destinationLength, + bool forEscape) { uint256_t amount, amountPre, quantum; uint8_t decimals; - char *ticker = (char *) PIC(chainConfig->coinName); + char *ticker = chainConfig->coinName; if ((amountData == NULL) || (forEscape && (dataContext.tokenContext.quantumIndex == MAX_TOKEN))) { @@ -310,7 +314,7 @@ void starkware_print_amount(uint8_t *amountData, char *destination, bool forEsca tokenDefinition_t *token = &tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex]; decimals = token->decimals; - ticker = (char *) token->ticker; + ticker = token->ticker; readu256BE(amountData, &amountPre); } if (amountData != NULL) { @@ -318,35 +322,35 @@ void starkware_print_amount(uint8_t *amountData, char *destination, bool forEsca mul256(&amountPre, &quantum, &amount); } tostring256(&amount, 10, (char *) (G_io_apdu_buffer + 100), 100); - strcpy(destination, ticker); + strlcpy(destination, ticker, destinationLength); adjustDecimals((char *) (G_io_apdu_buffer + 100), strlen((char *) (G_io_apdu_buffer + 100)), destination + strlen(ticker), - 50 - strlen(ticker), + destinationLength - strlen(ticker), decimals); } // TODO : rewrite as independant code -void starkware_print_ticker(char *destination) { - char *ticker = (char *) PIC(chainConfig->coinName); +void starkware_print_ticker(char *destination, size_t destinationLength) { + char *ticker = chainConfig->coinName; if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) { tokenDefinition_t *token = &tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex]; - ticker = (char *) token->ticker; + ticker = token->ticker; } - strcpy(destination, ticker); + strlcpy(destination, ticker, destinationLength); } // TODO : rewrite as independant code -void starkware_print_asset_contract(char *destination) { +void starkware_print_asset_contract(char *destination, size_t destinationLength) { // token has been validated to be present previously if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) { tokenDefinition_t *token = &tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex]; - starkware_print_eth_address(token->address, destination); + starkware_print_eth_address(token->address, destination, destinationLength); } else { - strcpy(destination, "UNKNOWN"); + strlcpy(destination, "UNKNOWN", destinationLength); } } @@ -368,10 +372,7 @@ void starkware_get_source_address(char *destination) { io_seproxyhal_io_heartbeat(); destination[0] = '0'; destination[1] = 'x'; - getEthAddressStringFromKey(&publicKey, - (uint8_t *) (destination + 2), - &global_sha3, - chainConfig); + getEthAddressStringFromKey(&publicKey, destination + 2, &global_sha3, chainConfig); destination[42] = '\0'; } @@ -646,54 +647,55 @@ void starkware_plugin_call(int message, void *parameters) { PRINTF("starkware query contract id\n"); switch (context->selectorIndex) { case STARKWARE_REGISTER: - strcpy(msg->name, "Register"); + strlcpy(msg->name, "Register", msg->nameLength); break; case STARKWARE_DEPOSIT_TOKEN: case STARKWARE_DEPOSIT_ETH: case STARKWARE_DEPOSIT_NFT: case STARKWARE_PROXY_DEPOSIT_TOKEN: case STARKWARE_PROXY_DEPOSIT_ETH: - strcpy(msg->name, "Deposit"); + strlcpy(msg->name, "Deposit", msg->nameLength); break; case STARKWARE_DEPOSIT_CANCEL: - strcpy(msg->name, "Cancel Deposit"); + strlcpy(msg->name, "Cancel Deposit", msg->nameLength); break; case STARKWARE_DEPOSIT_RECLAIM: case STARKWARE_DEPOSIT_NFT_RECLAIM: - strcpy(msg->name, "Reclaim Deposit"); + strlcpy(msg->name, "Reclaim Deposit", msg->nameLength); break; case STARKWARE_WITHDRAW: case STARKWARE_WITHDRAW_NFT: case STARKWARE_WITHDRAW_AND_MINT: - strcpy(msg->name, "Withdrawal"); + strlcpy(msg->name, "Withdrawal", msg->nameLength); break; case STARKWARE_FULL_WITHDRAW: - strcpy(msg->name, "Full Withdrawal"); + strlcpy(msg->name, "Full Withdrawal", msg->nameLength); break; case STARKWARE_FREEZE: - strcpy(msg->name, "Freeze"); + strlcpy(msg->name, "Freeze", msg->nameLength); break; case STARKWARE_ESCAPE: - strcpy(msg->name, "Escape"); + strlcpy(msg->name, "Escape", msg->nameLength); break; case STARKWARE_VERIFY_ESCAPE: - strcpy(msg->name, "Verify Escape"); + strlcpy(msg->name, "Verify Escape", msg->nameLength); break; case STARKWARE_WITHDRAW_TO: case STARKWARE_WITHDRAW_NFT_TO: - strcpy(msg->name, "Withdrawal To"); + strlcpy(msg->name, "Withdrawal To", msg->nameLength); break; case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN: case STARKWARE_REGISTER_AND_DEPOSIT_ETH: - strcpy(msg->name, "Register&Deposit"); + strlcpy(msg->name, "Register&Deposit", msg->nameLength); break; default: break; } - strcpy(msg->version, - is_deversify_contract(tmpContent.txContent.destination) ? "DeversiFi" - : "Starkware"); + strlcpy( + msg->version, + is_deversify_contract(tmpContent.txContent.destination) ? "DeversiFi" : "Starkware", + msg->versionLength); msg->result = ETH_PLUGIN_RESULT_OK; } break; @@ -702,11 +704,13 @@ void starkware_plugin_call(int message, void *parameters) { starkware_parameters_t *context = (starkware_parameters_t *) msg->pluginContext; switch (msg->screenIndex) { case 0: - strcpy(msg->title, "Contract Name"); + strlcpy(msg->title, "Contract Name", msg->titleLength); if (is_deversify_contract(tmpContent.txContent.destination)) { - strcpy(msg->msg, "DeversiFi"); + strlcpy(msg->msg, "DeversiFi", msg->msgLength); } else { - starkware_print_eth_address(tmpContent.txContent.destination, msg->msg); + starkware_print_eth_address(tmpContent.txContent.destination, + msg->msg, + msg->msgLength); } msg->result = ETH_PLUGIN_RESULT_OK; break; @@ -715,12 +719,12 @@ void starkware_plugin_call(int message, void *parameters) { case STARKWARE_REGISTER: case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN: case STARKWARE_REGISTER_AND_DEPOSIT_ETH: - strcpy(msg->title, "From ETH Address"); - starkware_print_eth_address(context->amount, msg->msg); + strlcpy(msg->title, "From ETH Address", msg->titleLength); + starkware_print_eth_address(context->amount, msg->msg, msg->msgLength); break; case STARKWARE_ESCAPE: - strcpy(msg->title, "Amount"); - starkware_print_amount(context->amount, msg->msg, true); + strlcpy(msg->title, "Amount", msg->titleLength); + starkware_print_amount(context->amount, msg->msg, msg->msgLength, true); break; case STARKWARE_DEPOSIT_TOKEN: case STARKWARE_DEPOSIT_ETH: @@ -738,7 +742,7 @@ void starkware_plugin_call(int message, void *parameters) { case STARKWARE_WITHDRAW_AND_MINT: case STARKWARE_WITHDRAW_NFT: case STARKWARE_WITHDRAW_NFT_TO: - strcpy(msg->title, "Master Account"); + strlcpy(msg->title, "Master Account", msg->titleLength); starkware_print_stark_key(context->starkKey, msg->msg); break; default: @@ -755,7 +759,7 @@ void starkware_plugin_call(int message, void *parameters) { case STARKWARE_ESCAPE: case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN: case STARKWARE_REGISTER_AND_DEPOSIT_ETH: - strcpy(msg->title, "Master Account"); + strlcpy(msg->title, "Master Account", msg->titleLength); starkware_print_stark_key(context->starkKey, msg->msg); break; @@ -769,22 +773,22 @@ void starkware_plugin_call(int message, void *parameters) { case STARKWARE_FREEZE: case STARKWARE_DEPOSIT_NFT: case STARKWARE_DEPOSIT_NFT_RECLAIM: - strcpy(msg->title, "Token Account"); + strlcpy(msg->title, "Token Account", msg->titleLength); starkware_print_vault_id(U4BE(context->vaultId, 0), msg->msg); break; case STARKWARE_WITHDRAW: case STARKWARE_WITHDRAW_NFT: - strcpy(msg->title, "To ETH Address"); + strlcpy(msg->title, "To ETH Address", msg->titleLength); starkware_get_source_address(msg->msg); break; case STARKWARE_WITHDRAW_TO: case STARKWARE_WITHDRAW_NFT_TO: - strcpy(msg->title, "To ETH Address"); - starkware_print_eth_address(context->amount, msg->msg); + strlcpy(msg->title, "To ETH Address", msg->titleLength); + starkware_print_eth_address(context->amount, msg->msg, msg->msgLength); break; case STARKWARE_WITHDRAW_AND_MINT: - strcpy(msg->title, "Asset Contract"); - starkware_print_asset_contract(msg->msg); + strlcpy(msg->title, "Asset Contract", msg->titleLength); + starkware_print_asset_contract(msg->msg, msg->msgLength); break; default: @@ -799,39 +803,40 @@ void starkware_plugin_call(int message, void *parameters) { case 3: switch (context->selectorIndex) { case STARKWARE_ESCAPE: - strcpy(msg->title, "Token Account"); + strlcpy(msg->title, "Token Account", msg->titleLength); starkware_print_vault_id(U4BE(context->vaultId, 0), msg->msg); break; case STARKWARE_DEPOSIT_TOKEN: case STARKWARE_DEPOSIT_ETH: case STARKWARE_PROXY_DEPOSIT_TOKEN: case STARKWARE_PROXY_DEPOSIT_ETH: - strcpy(msg->title, "Amount"); + strlcpy(msg->title, "Amount", msg->titleLength); starkware_print_amount( (((context->selectorIndex == STARKWARE_DEPOSIT_ETH) || (context->selectorIndex == STARKWARE_PROXY_DEPOSIT_ETH)) ? NULL : context->amount), msg->msg, + msg->msgLength, false); break; case STARKWARE_WITHDRAW: case STARKWARE_WITHDRAW_TO: - strcpy(msg->title, "Token Symbol"); - starkware_print_ticker(msg->msg); + strlcpy(msg->title, "Token Symbol", msg->titleLength); + starkware_print_ticker(msg->msg, msg->msgLength); break; case STARKWARE_WITHDRAW_NFT: case STARKWARE_WITHDRAW_NFT_TO: case STARKWARE_DEPOSIT_NFT: case STARKWARE_DEPOSIT_NFT_RECLAIM: - strcpy(msg->title, "NFT Contract"); - starkware_print_asset_contract(msg->msg); + strlcpy(msg->title, "NFT Contract", msg->titleLength); + starkware_print_asset_contract(msg->msg, msg->msgLength); break; case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN: case STARKWARE_REGISTER_AND_DEPOSIT_ETH: - strcpy(msg->title, "Token Account"); + strlcpy(msg->title, "Token Account", msg->titleLength); starkware_print_vault_id(U4BE(context->vaultId, 0), msg->msg); break; @@ -850,18 +855,19 @@ void starkware_plugin_call(int message, void *parameters) { case STARKWARE_WITHDRAW_NFT_TO: case STARKWARE_DEPOSIT_NFT: case STARKWARE_DEPOSIT_NFT_RECLAIM: - strcpy(msg->title, "TokenID"); + strlcpy(msg->title, "TokenID", msg->titleLength); starkware_print_stark_key(dataContext.tokenContext.quantum, msg->msg); break; case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN: case STARKWARE_REGISTER_AND_DEPOSIT_ETH: - strcpy(msg->title, "Amount"); + strlcpy(msg->title, "Amount", msg->titleLength); starkware_print_amount( ((context->selectorIndex == STARKWARE_REGISTER_AND_DEPOSIT_ETH) ? NULL : context->amount), msg->msg, + msg->msgLength, false); break; diff --git a/tests/elfs/ethereum_nanos.elf b/tests/elfs/ethereum_nanos.elf deleted file mode 100755 index 72e7f00..0000000 Binary files a/tests/elfs/ethereum_nanos.elf and /dev/null differ diff --git a/tests/elfs/ethereum_nanox.elf b/tests/elfs/ethereum_nanox.elf deleted file mode 100755 index 8e9e009..0000000 Binary files a/tests/elfs/ethereum_nanox.elf and /dev/null differ diff --git a/tests/snapshots/send/nanos/network.png b/tests/snapshots/send/nanos/network.png new file mode 100644 index 0000000..9dde424 Binary files /dev/null and b/tests/snapshots/send/nanos/network.png differ diff --git a/tests/snapshots/send/nanox/network.png b/tests/snapshots/send/nanox/network.png new file mode 100644 index 0000000..eb4b7b8 Binary files /dev/null and b/tests/snapshots/send/nanox/network.png differ diff --git a/tests/snapshots/send_bsc/nanos/amount_1.png b/tests/snapshots/send_bsc/nanos/amount_1.png index 4cd3e38..a25e91e 100644 Binary files a/tests/snapshots/send_bsc/nanos/amount_1.png and b/tests/snapshots/send_bsc/nanos/amount_1.png differ diff --git a/tests/snapshots/send_bsc/nanos/chainid.png b/tests/snapshots/send_bsc/nanos/chainid.png deleted file mode 100644 index acfe3d3..0000000 Binary files a/tests/snapshots/send_bsc/nanos/chainid.png and /dev/null differ diff --git a/tests/snapshots/send_bsc/nanos/fees.png b/tests/snapshots/send_bsc/nanos/fees.png index 2c12e0a..6a16a42 100644 Binary files a/tests/snapshots/send_bsc/nanos/fees.png and b/tests/snapshots/send_bsc/nanos/fees.png differ diff --git a/tests/snapshots/send_bsc/nanos/network.png b/tests/snapshots/send_bsc/nanos/network.png new file mode 100644 index 0000000..ef98ec6 Binary files /dev/null and b/tests/snapshots/send_bsc/nanos/network.png differ diff --git a/tests/snapshots/send_bsc/nanox/amount.png b/tests/snapshots/send_bsc/nanox/amount.png index c4f9260..9911bf3 100644 Binary files a/tests/snapshots/send_bsc/nanox/amount.png and b/tests/snapshots/send_bsc/nanox/amount.png differ diff --git a/tests/snapshots/send_bsc/nanox/chainid.png b/tests/snapshots/send_bsc/nanox/chainid.png deleted file mode 100644 index 53424d9..0000000 Binary files a/tests/snapshots/send_bsc/nanox/chainid.png and /dev/null differ diff --git a/tests/snapshots/send_bsc/nanox/fees.png b/tests/snapshots/send_bsc/nanox/fees.png index 71a1ef9..ac5d9db 100644 Binary files a/tests/snapshots/send_bsc/nanox/fees.png and b/tests/snapshots/send_bsc/nanox/fees.png differ diff --git a/tests/snapshots/send_bsc/nanox/network.png b/tests/snapshots/send_bsc/nanox/network.png new file mode 100644 index 0000000..b021901 Binary files /dev/null and b/tests/snapshots/send_bsc/nanox/network.png differ diff --git a/tests/snapshots/send_etc/nanos/accept.png b/tests/snapshots/send_etc/nanos/accept.png new file mode 100644 index 0000000..3158ea6 Binary files /dev/null and b/tests/snapshots/send_etc/nanos/accept.png differ diff --git a/tests/snapshots/send_etc/nanos/address_1.png b/tests/snapshots/send_etc/nanos/address_1.png new file mode 100644 index 0000000..f979f71 Binary files /dev/null and b/tests/snapshots/send_etc/nanos/address_1.png differ diff --git a/tests/snapshots/send_etc/nanos/address_2.png b/tests/snapshots/send_etc/nanos/address_2.png new file mode 100644 index 0000000..93c90c5 Binary files /dev/null and b/tests/snapshots/send_etc/nanos/address_2.png differ diff --git a/tests/snapshots/send_etc/nanos/address_3.png b/tests/snapshots/send_etc/nanos/address_3.png new file mode 100644 index 0000000..402c20d Binary files /dev/null and b/tests/snapshots/send_etc/nanos/address_3.png differ diff --git a/tests/snapshots/send_etc/nanos/amount_1.png b/tests/snapshots/send_etc/nanos/amount_1.png new file mode 100644 index 0000000..660399c Binary files /dev/null and b/tests/snapshots/send_etc/nanos/amount_1.png differ diff --git a/tests/snapshots/send_etc/nanos/amount_2.png b/tests/snapshots/send_etc/nanos/amount_2.png new file mode 100644 index 0000000..11ae75e Binary files /dev/null and b/tests/snapshots/send_etc/nanos/amount_2.png differ diff --git a/tests/snapshots/send_etc/nanos/amount_3.png b/tests/snapshots/send_etc/nanos/amount_3.png new file mode 100644 index 0000000..e042010 Binary files /dev/null and b/tests/snapshots/send_etc/nanos/amount_3.png differ diff --git a/tests/snapshots/send_etc/nanos/fees.png b/tests/snapshots/send_etc/nanos/fees.png new file mode 100644 index 0000000..85a8960 Binary files /dev/null and b/tests/snapshots/send_etc/nanos/fees.png differ diff --git a/tests/snapshots/send_etc/nanos/review.png b/tests/snapshots/send_etc/nanos/review.png new file mode 100644 index 0000000..2994983 Binary files /dev/null and b/tests/snapshots/send_etc/nanos/review.png differ diff --git a/tests/snapshots/send_etc/nanox/accept.png b/tests/snapshots/send_etc/nanox/accept.png new file mode 100644 index 0000000..7f2b8c8 Binary files /dev/null and b/tests/snapshots/send_etc/nanox/accept.png differ diff --git a/tests/snapshots/send_etc/nanox/address.png b/tests/snapshots/send_etc/nanox/address.png new file mode 100644 index 0000000..ce3e586 Binary files /dev/null and b/tests/snapshots/send_etc/nanox/address.png differ diff --git a/tests/snapshots/send_etc/nanox/amount.png b/tests/snapshots/send_etc/nanox/amount.png new file mode 100644 index 0000000..e83449a Binary files /dev/null and b/tests/snapshots/send_etc/nanox/amount.png differ diff --git a/tests/snapshots/send_etc/nanox/fees.png b/tests/snapshots/send_etc/nanox/fees.png new file mode 100644 index 0000000..2a101ca Binary files /dev/null and b/tests/snapshots/send_etc/nanox/fees.png differ diff --git a/tests/snapshots/send_etc/nanox/review.png b/tests/snapshots/send_etc/nanox/review.png new file mode 100644 index 0000000..8794afe Binary files /dev/null and b/tests/snapshots/send_etc/nanox/review.png differ diff --git a/tests/src/generic.js b/tests/src/generic.js index 59968b4..2fdcd2b 100644 --- a/tests/src/generic.js +++ b/tests/src/generic.js @@ -18,11 +18,21 @@ const Resolve = require("path").resolve; const NANOS_ELF_PATH = Resolve("elfs/ethereum_nanos.elf"); const NANOX_ELF_PATH = Resolve("elfs/ethereum_nanox.elf"); +const NANOS_ETH_LIB = { "Ethereum": NANOS_ELF_PATH }; +const NANOX_ETH_LIB = { "Ethereum": NANOX_ELF_PATH }; + +const NANOS_CLONE_ELF_PATH = Resolve("elfs/ethereum_classic_nanos.elf"); +const NANOX_CLONE_ELF_PATH = Resolve("elfs/ethereum_classic_nanox.elf"); + const TIMEOUT = 1000000; module.exports = { NANOS_ELF_PATH, NANOX_ELF_PATH, + NANOS_ETH_LIB, + NANOX_ETH_LIB, + NANOS_CLONE_ELF_PATH, + NANOX_CLONE_ELF_PATH, sim_options_nanos, sim_options_nanox, TIMEOUT, diff --git a/tests/src/send.test.js b/tests/src/send.test.js index 37cbdee..7deb7c7 100644 --- a/tests/src/send.test.js +++ b/tests/src/send.test.js @@ -17,7 +17,7 @@ const ORIGINAL_SNAPSHOT_PATH_NANOX = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanox/"; const SNAPSHOT_PATH_NANOS = SNAPSHOT_PATH_PREFIX + "nanos/"; const SNAPSHOT_PATH_NANOX = SNAPSHOT_PATH_PREFIX + "nanox/"; -test("Transfer nanos", async () => { +test("Transfer Ether on Ethereum app nanos", async () => { jest.setTimeout(TIMEOUT); const sim = new Zemu(NANOS_ELF_PATH); @@ -106,7 +106,103 @@ test("Transfer nanos", async () => { } }); -test("Transfer nanox", async () => { +test("Transfer on network 5234 on Ethereum nanos", async () => { + jest.setTimeout(TIMEOUT); + const sim = new Zemu(NANOS_ELF_PATH); + + try { + await sim.start(sim_options_nanos); + + let transport = await sim.getTransport(); + + let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex"); + + // Send transaction + let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer); + let filename; + + await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot()); + // Review tx + filename = "review.png"; + await sim.snapshot(SNAPSHOT_PATH_NANOS + filename); + const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(review).toEqual(expected_review); + + // Amount 1/3 + filename = "amount_1.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const amount_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_amount_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(amount_1).toEqual(expected_amount_1); + + // Amount 2/3 + filename = "amount_2.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const amount_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_amount_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(amount_2).toEqual(expected_amount_2); + + // Amount 3/3 + filename = "amount_3.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const amount_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_amount_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(amount_3).toEqual(expected_amount_3); + + // Address 1/3 + filename = "address_1.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const address_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(address_1).toEqual(expected_address_1); + + // Address 2/3 + filename = "address_2.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const address_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(address_2).toEqual(expected_address_2); + + // Address 3/3 + filename = "address_3.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const address_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(address_3).toEqual(expected_address_3); + + // Network + filename = "network.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const network = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(network).toEqual(expected_network); + + // Max Fees + filename = "fees.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(fees).toEqual(expected_fees); + + // Accept + filename = "accept.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(accept).toEqual(expected_accept); + + await sim.clickBoth(); + + await expect(tx).resolves.toEqual( + Buffer.from("08f3449bbc245669e26dd076986e11aa3117e2405ffe2ddc7a7e220f81326fbd91150515605c78119367be311345e9ff40c4e4ddb9ec0fd81f37035c3828f4c8b29000", 'hex') + ); + } finally { + await sim.close(); + } +}); + +test("Transfer Ether on Ethereum nanox", async () => { jest.setTimeout(TIMEOUT); const sim = new Zemu(NANOX_ELF_PATH); @@ -164,4 +260,73 @@ test("Transfer nanox", async () => { } finally { await sim.close(); } +}); + + +test("Transfer on network 5234 on Ethereum nanox", async () => { + jest.setTimeout(TIMEOUT); + const sim = new Zemu(NANOX_ELF_PATH); + + try { + await sim.start(sim_options_nanox); + + let transport = await sim.getTransport(); + + let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex"); + + // Send transaction + let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer); + let filename; + + await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot()); + // Review tx + filename = "review.png"; + await sim.snapshot(SNAPSHOT_PATH_NANOX + filename); + const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(review).toEqual(expected_review); + + // Amount + filename = "amount.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(amount).toEqual(expected_amount); + + // Address + filename = "address.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const address = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(address).toEqual(expected_address); + + // Network + filename = "network.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const network = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(network).toEqual(expected_network); + + // Max Fees + filename = "fees.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(fees).toEqual(expected_fees); + + // Accept + filename = "accept.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(accept).toEqual(expected_accept); + + await sim.clickBoth(); + + await expect(tx).resolves.toEqual( + Buffer.from("08f3449bbc245669e26dd076986e11aa3117e2405ffe2ddc7a7e220f81326fbd91150515605c78119367be311345e9ff40c4e4ddb9ec0fd81f37035c3828f4c8b29000", 'hex') + ); + } finally { + await sim.close(); + } }); \ No newline at end of file diff --git a/tests/src/send_bsc.test.js b/tests/src/send_bsc.test.js index dda50a3..028f6cb 100644 --- a/tests/src/send_bsc.test.js +++ b/tests/src/send_bsc.test.js @@ -83,8 +83,8 @@ test("Transfer bsc nanos", async () => { const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); expect(address_3).toEqual(expected_address_3); - // Chain ID - filename = "chainid.png"; + // Network name + filename = "network.png"; await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const expected_chainid = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); @@ -151,8 +151,8 @@ test("Transfer bsc nanox", async () => { const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); expect(address).toEqual(expected_address); - // Chain ID - filename = "chainid.png"; + // Network name + filename = "network.png"; await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); const expected_chainid = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); diff --git a/tests/src/send_etc.test.js b/tests/src/send_etc.test.js new file mode 100644 index 0000000..39da31c --- /dev/null +++ b/tests/src/send_etc.test.js @@ -0,0 +1,208 @@ +import "core-js/stable"; +import "regenerator-runtime/runtime"; +import Eth from "@ledgerhq/hw-app-eth"; +import { byContractAddress } from "@ledgerhq/hw-app-eth/erc20"; +import Zemu from "@zondax/zemu"; +import { TransportStatusError } from "@ledgerhq/errors"; +import { expect } from "../jest"; + +const {NANOS_ETH_LIB, NANOX_ETH_LIB, NANOS_CLONE_ELF_PATH, NANOX_CLONE_ELF_PATH, sim_options_nanos, sim_options_nanox, TIMEOUT} = require("generic.js"); + +const ORIGINAL_SNAPSHOT_PATH_PREFIX = "snapshots/send_etc/"; +const SNAPSHOT_PATH_PREFIX = "snapshots/tmp/"; + +const ORIGINAL_SNAPSHOT_PATH_NANOS = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanos/"; +const ORIGINAL_SNAPSHOT_PATH_NANOX = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanox/"; + +const SNAPSHOT_PATH_NANOS = SNAPSHOT_PATH_PREFIX + "nanos/"; +const SNAPSHOT_PATH_NANOX = SNAPSHOT_PATH_PREFIX + "nanox/"; + +test("Transfer on Ethereum clone app nanos", async () => { + jest.setTimeout(TIMEOUT); + const sim = new Zemu(NANOS_CLONE_ELF_PATH, NANOS_ETH_LIB); + + try { + await sim.start(sim_options_nanos); + + let transport = await sim.getTransport(); + + let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818803D8080", "hex"); + + // Send transaction + let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer); + let filename; + + await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot()); + // Review tx + filename = "review.png"; + await sim.snapshot(SNAPSHOT_PATH_NANOS + filename); + const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(review).toEqual(expected_review); + + // Amount 1/3 + filename = "amount_1.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const amount_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_amount_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(amount_1).toEqual(expected_amount_1); + + // Amount 2/3 + filename = "amount_2.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const amount_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_amount_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(amount_2).toEqual(expected_amount_2); + + // Amount 3/3 + filename = "amount_3.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const amount_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_amount_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(amount_3).toEqual(expected_amount_3); + + // Address 1/3 + filename = "address_1.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const address_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(address_1).toEqual(expected_address_1); + + // Address 2/3 + filename = "address_2.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const address_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(address_2).toEqual(expected_address_2); + + // Address 3/3 + filename = "address_3.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const address_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(address_3).toEqual(expected_address_3); + + // Max Fees + filename = "fees.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(fees).toEqual(expected_fees); + + // Accept + filename = "accept.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); + const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); + const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); + expect(accept).toEqual(expected_accept); + + await sim.clickBoth(); + await expect(tx).resolves.toEqual( + Buffer.from("9e52b80e10cb82f3dc8345005e3da3f9cae1fb3f2b9a5df05b7cedba786c685fed381875af27d121beaa9efd8a7450975f9d45a26ba5aa331b7a8b26bcce95e6d09000", 'hex') + ); + } finally { + await sim.close(); + } +}); + +test("Transfer on network 5234 on Ethereum clone nanos", async () => { + jest.setTimeout(TIMEOUT); + const sim = new Zemu(NANOS_CLONE_ELF_PATH, NANOS_ETH_LIB); + + try { + await sim.start(sim_options_nanos); + + let transport = await sim.getTransport(); + + let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex"); + + // Send transaction + let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer); + + await expect(tx).rejects.toEqual(new TransportStatusError(0x6a80)); + + } finally { + await sim.close(); + } +}); + +test("Transfer on Ethereum clone nanox", async () => { + jest.setTimeout(TIMEOUT); + const sim = new Zemu(NANOX_CLONE_ELF_PATH, NANOX_ETH_LIB); + + try { + await sim.start(sim_options_nanox); + + let transport = await sim.getTransport(); + let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818803D8080", "hex"); + + // Send transaction + let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer); + let filename; + + await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot()); + // Review tx + filename = "review.png"; + await sim.snapshot(SNAPSHOT_PATH_NANOX + filename); + const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(review).toEqual(expected_review); + + // Amount + filename = "amount.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(amount).toEqual(expected_amount); + + // Address + filename = "address.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const address = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(address).toEqual(expected_address); + + // Max Fees + filename = "fees.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(fees).toEqual(expected_fees); + + // Accept + filename = "accept.png"; + await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); + const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); + const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); + expect(accept).toEqual(expected_accept); + + await sim.clickBoth(); + + await expect(tx).resolves.toEqual( + Buffer.from("9e52b80e10cb82f3dc8345005e3da3f9cae1fb3f2b9a5df05b7cedba786c685fed381875af27d121beaa9efd8a7450975f9d45a26ba5aa331b7a8b26bcce95e6d09000", 'hex') + ); + } finally { + await sim.close(); + } +}); + + +test("Transfer on network 5234 on Ethereum clone nanox", async () => { + jest.setTimeout(TIMEOUT); + const sim = new Zemu(NANOX_CLONE_ELF_PATH, NANOX_ETH_LIB); + + try { + await sim.start(sim_options_nanox); + + let transport = await sim.getTransport(); + + let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex"); + + // Send transaction + let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer); + + await expect(tx).rejects.toEqual(new TransportStatusError(0x6a80)); + } finally { + await sim.close(); + } +}); \ No newline at end of file