Repository: LedgerHQ/app-ethereum (language: python)

Issue:
1.10.3 changelog update & non -dev version number
## Description

Release preparation.

## Changes include

- [ ] Bugfix (non-breaking change that solves an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (change that is not backwards-compatible and/or changes current functionality)
- [ ] Tests
- [ ] Documentation
- [x] Other (for changes that might not fit in any category)


Discussion / hints:

Fix patch:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 711779d18..a141a2d83 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -15,7 +15,7 @@ Describe your issue in as much detail as possible here.
 
 * OS and version
 * branch that causes this issue
-* Device (Nano S, Nano X, Ledger Blue)
+* Device (Nano S, Nano S Plus, Nano X, Ledger Blue)
 
 ## Steps to reproduce
 
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index f8abc5224..031ba337d 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -15,4 +15,4 @@ Describe your issue in as much detail as possible here.
 
 * OS and version
 * branch that causes this issue
-* Device (Nano S, Nano X, Ledger Blue)
\ No newline at end of file
+* Device (Nano S, Nano S Plus, Nano X, Ledger Blue)
diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml
index 3e15b7913..d5cf7959e 100644
--- a/.github/workflows/ci-workflow.yml
+++ b/.github/workflows/ci-workflow.yml
@@ -128,6 +128,7 @@ jobs:
   jobs-e2e-speculos-tests:
     name: Speculos tests
     strategy:
+      fail-fast: false
       matrix:
         model: ["nanosp", "nanos", "nanox"]
 
@@ -153,7 +154,7 @@ jobs:
         run: |
           cd tests/speculos
           sudo apt-get update && sudo apt-get install -y qemu-user-static
-          pip install --extra-index-url https://test.pypi.org/simple/ -r requirements.txt
+          pip install -r requirements.txt
 
       - name: Run speculos tests
         run: |
@@ -171,7 +172,6 @@ jobs:
     with:
       upload_app_binaries_artifact: "ragger_elfs"
       flags: "DEBUG=1 CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1"
-      run_for_devices: '["nanos", "nanox", "nanosp"]'
 
   jobs-ragger-tests:
     name: Run Ragger tests
@@ -180,4 +180,3 @@ jobs:
     with:
       download_app_binaries_artifact: "ragger_elfs"
       test_dir: tests/ragger
-      run_for_devices: '["nanos", "nanox", "nanosp"]'
diff --git a/.github/workflows/swap-ci-workflow.yml b/.github/workflows/swap-ci-workflow.yml
new file mode 100644
index 000000000..3999224cf
--- /dev/null
+++ b/.github/workflows/swap-ci-workflow.yml
@@ -0,0 +1,16 @@
+name: Swap functional tests
+
+on:
+  workflow_dispatch:
+  push:
+    branches:
+    - master
+    - develop
+  pull_request:
+
+jobs:
+  job_functional_tests:
+    uses: LedgerHQ/app-exchange/.github/workflows/reusable_swap_functional_tests.yml@develop
+    with:
+      branch_for_ethereum: ${{ github.ref }}
+      test_filter: '"ETH or eth or Ethereum or ethereum"'
diff --git a/.gitignore b/.gitignore
index 9443644b5..6779287da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ bin/
 debug/
 dep/
 obj/
+build/
 
 # Python
 *.pyc
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50c74f734..6cd99025a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,33 @@ 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.10.3](https://github.com/ledgerhq/app-ethereum/compare/1.10.2...1.10.3) - 2023-07-27
+
+### Added
+
+- (network) LUKSO mainnet & testnet
+- (network) Chiado
+- (network) PulseChain
+- (network) Neon EVM mainnet & devnet
+- (network) Venidium
+- (network) Telos EVM mainnet
+- (network) OKBChain mainnet
+- (network) Polygon zkEVM
+- (network) Base
+- (network) Sepolia
+- ENS on chains that share the Ethereum derivation path
+- Ledger Stax support
+
+### Changed
+
+- (network) xDai renamed to Gnosis
+
+### Fixed
+
+- Missing context cleanup between plugin calls
+- Miscellaneous swap issues
+- Improper EIP-712 array handling
+
 ## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2023-04-24
 
 ### Added
diff --git a/Makefile b/Makefile
index b7704d763..4715da52a 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
 
 APPVERSION_M=1
 APPVERSION_N=10
-APPVERSION_P=2
+APPVERSION_P=3
 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
 APP_LOAD_FLAGS= --appFlags 0xa40 --dep Ethereum:$(APPVERSION)
 
@@ -54,6 +54,7 @@ include ./makefile_conf/chain/$(CHAIN).mk
 else
 $(error Unsupported CHAIN - use $(SUPPORTED_CHAINS))
 endif
+CFLAGS += -DAPPNAME=\"$(APPNAME)\"
 
 #########
 # Other #
@@ -65,6 +66,12 @@ DEFINES += $(DEFINES_LIB)
 #prepare hsm generation
 ifeq ($(TARGET_NAME),TARGET_NANOS)
 ICONNAME=icons/nanos_app_$(CHAIN).gif
+else ifeq ($(TARGET_NAME),TARGET_STAX)
+ICONNAME=icons/stax_app_$(CHAIN).gif
+DEFINES += ICONGLYPH=C_stax_$(CHAIN)_64px
+DEFINES += ICONBITMAP=C_stax_$(CHAIN)_64px_bitmap
+DEFINES += ICONGLYPH_SMALL=C_stax_$(CHAIN)
+GLYPH_FILES += $(ICONNAME)
 else
 ICONNAME=icons/nanox_app_$(CHAIN).gif
 endif
@@ -79,9 +86,10 @@ all: default
 ############
 
 DEFINES   += OS_IO_SEPROXYHAL
-DEFINES   += HAVE_BAGL HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U
+DEFINES   += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U
 DEFINES   += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
 DEFINES   += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P)
+DEFINES   += BUILD_YEAR=\"$(shell date +%Y)\"
 
 # U2F
 DEFINES   += HAVE_U2F HAVE_IO_U2F
@@ -90,30 +98,41 @@ DEFINES   += USB_SEGMENT_SIZE=64
 DEFINES   += BLE_SEGMENT_SIZE=32 #max MTU, min 20
 DEFINES   += UNUSED\(x\)=\(void\)x
 DEFINES   += APPVERSION=\"$(APPVERSION)\"
-DEFINES   += HAVE_UX_FLOW
 
 #WEBUSB_URL     = www.ledgerwallet.com
 #DEFINES       += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g")
 
 DEFINES   += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL=""
 
-ifeq ($(TARGET_NAME),TARGET_NANOX)
+ifneq (,$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX))
 DEFINES   += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000
 DEFINES   += HAVE_BLE_APDU # basic ledger apdu transport over BLE
+SDK_SOURCE_PATH  += lib_blewbxx lib_blewbxx_impl
 endif
 
 ifeq ($(TARGET_NAME),TARGET_NANOS)
-DEFINES   += IO_SEPROXYHAL_BUFFER_SIZE_B=72
-DEFINES   += HAVE_WALLET_ID_SDK
+DEFINES   += IO_SEPROXYHAL_BUFFER_SIZE_B=128
 else
 DEFINES   += IO_SEPROXYHAL_BUFFER_SIZE_B=300
+endif
+
+ifeq  ($(TARGET_NAME),TARGET_STAX)
+DEFINES   += NBGL_QRCODE
+else
+DEFINES   += HAVE_BAGL
+DEFINES   += HAVE_UX_FLOW
+ifeq ($(TARGET_NAME),TARGET_NANOS)
+DEFINES   += HAVE_WALLET_ID_SDK
+DEFINES   += BAGL_WIDTH=128 BAGL_HEIGHT=32
+else
 DEFINES   += HAVE_GLO096
-DEFINES   += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64
+DEFINES   += BAGL_WIDTH=128 BAGL_HEIGHT=64
 DEFINES   += HAVE_BAGL_ELLIPSIS # long label truncation feature
 DEFINES   += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX
 DEFINES   += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX
 DEFINES   += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX
 endif
+endif
 
 # Enables direct data signing without having to specify it in the settings. Useful when testing with speculos.
 ALLOW_DATA:=0
@@ -167,7 +186,6 @@ endif
 endif
 
 # Enabling debug PRINTF
-DEBUG:=0
 ifneq ($(DEBUG),0)
 DEFINES += HAVE_STACK_OVERFLOW_CHECK
 ifeq ($(TARGET_NAME),TARGET_NANOS)
@@ -204,13 +222,11 @@ endif
 
 CC       := $(CLANGPATH)clang
 
-#CFLAGS   += -O0
-CFLAGS   += -Oz -Wno-format-invalid-specifier -Wno-format-extra-args
+CFLAGS   += -Wno-format-invalid-specifier -Wno-format-extra-args
 
 AS     := $(GCCPATH)arm-none-eabi-gcc
 
 LD       := $(GCCPATH)arm-none-eabi-gcc
-LDFLAGS  += -O3 -Os
 LDLIBS   += -lm -lgcc -lc
 
 # import rules to compile glyphs(/pone)
@@ -219,11 +235,12 @@ include $(BOLOS_SDK)/Makefile.glyphs
 ### variables processed by the common makefile.rules of the SDK to grab source files and include dirs
 APP_SOURCE_PATH  += src_common src src_features src_plugins
 SDK_SOURCE_PATH  += lib_stusb lib_stusb_impl lib_u2f
+ifeq  ($(TARGET_NAME),TARGET_STAX)
+APP_SOURCE_PATH  += src_nbgl
+else
 SDK_SOURCE_PATH  += lib_ux
-ifeq ($(TARGET_NAME),TARGET_NANOX)
-SDK_SOURCE_PATH  += lib_blewbxx lib_blewbxx_impl
-endif
 APP_SOURCE_PATH  += src_bagl
+endif
 
 ### initialize plugin SDK submodule if needed, rebuild it, and warn if a difference is noticed
 ifeq ($(CHAIN),ethereum)
diff --git a/README.md b/README.md
index 789a604aa..0293c3194 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
   <h1 align="center">app-ethereum</h1>
 
   <p align="center">
-    Ethereum wallet application for Ledger Blue, Nano S and Nano X
+    Ethereum wallet application for Ledger Blue, Nano S, Nano S Plus and Nano X
     <br />
     <a href="https://github.com/LedgerHQ/app-ethereum/tree/master/doc"><strong>« Explore the docs »</strong></a>
     <br />
@@ -42,7 +42,7 @@
 
 ## About the project
 
-Ethereum wallet application framework for Nano S and Nano X.  
+Ethereum wallet application framework for Nano S, Nano S Plus 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`](https://github.com/LedgerHQ/app-ethereum/tree/blue-final-release).
 
 ## Documentation
diff --git a/ethereum-plugin-sdk b/ethereum-plugin-sdk
index a4b971f67..b9777e7a8 160000
--- a/ethereum-plugin-sdk
+++ b/ethereum-plugin-sdk
@@ -1,1 +1,1 @@
-Subproject commit a4b971f67980694d8c3862e793859209bc525545
+Subproject commit b9777e7a81a9c33b3f8997ffa23396fa2b3f861d
diff --git a/glyphs/badge_transaction.gif b/glyphs/badge_transaction.gif
deleted file mode 100644
index 131325d4a..000000000
Binary files a/glyphs/badge_transaction.gif and /dev/null differ
diff --git a/glyphs/blue_badge_akroma.gif b/glyphs/blue_badge_akroma.gif
deleted file mode 100644
index 40b3320c4..000000000
Binary files a/glyphs/blue_badge_akroma.gif and /dev/null differ
diff --git a/glyphs/blue_badge_atheios.gif b/glyphs/blue_badge_atheios.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_atheios.gif and /dev/null differ
diff --git a/glyphs/blue_badge_callisto.gif b/glyphs/blue_badge_callisto.gif
deleted file mode 100644
index 43a8c3563..000000000
Binary files a/glyphs/blue_badge_callisto.gif and /dev/null differ
diff --git a/glyphs/blue_badge_dexon.gif b/glyphs/blue_badge_dexon.gif
deleted file mode 100644
index 9b4dd9e7c..000000000
Binary files a/glyphs/blue_badge_dexon.gif and /dev/null differ
diff --git a/glyphs/blue_badge_ellaism.gif b/glyphs/blue_badge_ellaism.gif
deleted file mode 100644
index cb4d811e4..000000000
Binary files a/glyphs/blue_badge_ellaism.gif and /dev/null differ
diff --git a/glyphs/blue_badge_eosclassic.gif b/glyphs/blue_badge_eosclassic.gif
deleted file mode 100644
index 3ad0bbaad..000000000
Binary files a/glyphs/blue_badge_eosclassic.gif and /dev/null differ
diff --git a/glyphs/blue_badge_ether1.gif b/glyphs/blue_badge_ether1.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_ether1.gif and /dev/null differ
diff --git a/glyphs/blue_badge_ethereum.gif b/glyphs/blue_badge_ethereum.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_ethereum.gif and /dev/null differ
diff --git a/glyphs/blue_badge_ethereum_classic.gif b/glyphs/blue_badge_ethereum_classic.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_ethereum_classic.gif and /dev/null differ
diff --git a/glyphs/blue_badge_ethergem.gif b/glyphs/blue_badge_ethergem.gif
deleted file mode 100644
index 01676ade0..000000000
Binary files a/glyphs/blue_badge_ethergem.gif and /dev/null differ
diff --git a/glyphs/blue_badge_ethersocial.gif b/glyphs/blue_badge_ethersocial.gif
deleted file mode 100644
index 011545f63..000000000
Binary files a/glyphs/blue_badge_ethersocial.gif and /dev/null differ
diff --git a/glyphs/blue_badge_expanse.gif b/glyphs/blue_badge_expanse.gif
deleted file mode 100644
index 9de8e125c..000000000
Binary files a/glyphs/blue_badge_expanse.gif and /dev/null differ
diff --git a/glyphs/blue_badge_gochain.gif b/glyphs/blue_badge_gochain.gif
deleted file mode 100644
index 4a8ea11eb..000000000
Binary files a/glyphs/blue_badge_gochain.gif and /dev/null differ
diff --git a/glyphs/blue_badge_hpb.gif b/glyphs/blue_badge_hpb.gif
deleted file mode 100644
index 3b64b0c2a..000000000
Binary files a/glyphs/blue_badge_hpb.gif and /dev/null differ
diff --git a/glyphs/blue_badge_mix.gif b/glyphs/blue_badge_mix.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_mix.gif and /dev/null differ
diff --git a/glyphs/blue_badge_musicoin.gif b/glyphs/blue_badge_musicoin.gif
deleted file mode 100644
index c56081dfc..000000000
Binary files a/glyphs/blue_badge_musicoin.gif and /dev/null differ
diff --git a/glyphs/blue_badge_pirl.gif b/glyphs/blue_badge_pirl.gif
deleted file mode 100644
index 19a25f9ff..000000000
Binary files a/glyphs/blue_badge_pirl.gif and /dev/null differ
diff --git a/glyphs/blue_badge_poa.gif b/glyphs/blue_badge_poa.gif
deleted file mode 100644
index 62d6c065b..000000000
Binary files a/glyphs/blue_badge_poa.gif and /dev/null differ
diff --git a/glyphs/blue_badge_reosc.gif b/glyphs/blue_badge_reosc.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_reosc.gif and /dev/null differ
diff --git a/glyphs/blue_badge_ropsten.gif b/glyphs/blue_badge_ropsten.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_ropsten.gif and /dev/null differ
diff --git a/glyphs/blue_badge_rsk.gif b/glyphs/blue_badge_rsk.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_rsk.gif and /dev/null differ
diff --git a/glyphs/blue_badge_thundercore.gif b/glyphs/blue_badge_thundercore.gif
deleted file mode 100644
index a31bbe32d..000000000
Binary files a/glyphs/blue_badge_thundercore.gif and /dev/null differ
diff --git a/glyphs/blue_badge_tomochain.gif b/glyphs/blue_badge_tomochain.gif
deleted file mode 100644
index 624837f5a..000000000
Binary files a/glyphs/blue_badge_tomochain.gif and /dev/null differ
diff --git a/glyphs/blue_badge_ubiq.gif b/glyphs/blue_badge_ubiq.gif
deleted file mode 100644
index 69b1cf3ae..000000000
Binary files a/glyphs/blue_badge_ubiq.gif and /dev/null differ
diff --git a/glyphs/blue_badge_wanchain.gif b/glyphs/blue_badge_wanchain.gif
deleted file mode 100644
index deb64841e..000000000
Binary files a/glyphs/blue_badge_wanchain.gif and /dev/null differ
diff --git a/glyphs/blue_badge_webchain.gif b/glyphs/blue_badge_webchain.gif
deleted file mode 100644
index 24edd1c2a..000000000
Binary files a/glyphs/blue_badge_webchain.gif and /dev/null differ
diff --git a/glyphs/icon_back.gif b/glyphs/icon_back.gif
deleted file mode 100644
index a2a7e6d4f..000000000
Binary files a/glyphs/icon_back.gif and /dev/null differ
diff --git a/glyphs/icon_back_x.gif b/glyphs/icon_back_x.gif
deleted file mode 100644
index ff043615c..000000000
Binary files a/glyphs/icon_back_x.gif and /dev/null differ
diff --git a/glyphs/icon_certificate.gif b/glyphs/icon_certificate.gif
deleted file mode 100644
index 89b529f79..000000000
Binary files a/glyphs/icon_certificate.gif and /dev/null differ
diff --git a/glyphs/icon_crossmark.gif b/glyphs/icon_crossmark.gif
deleted file mode 100644
index 2dcf9d9ee..000000000
Binary files a/glyphs/icon_crossmark.gif and /dev/null differ
diff --git a/glyphs/icon_dashboard.gif b/glyphs/icon_dashboard.gif
deleted file mode 100644
index 5c305517f..000000000
Binary files a/glyphs/icon_dashboard.gif and /dev/null differ
diff --git a/glyphs/icon_dashboard_x.gif b/glyphs/icon_dashboard_x.gif
deleted file mode 100644
index 33d9b0a74..000000000
Binary files a/glyphs/icon_dashboard_x.gif and /dev/null differ
diff --git a/glyphs/icon_down.gif b/glyphs/icon_down.gif
deleted file mode 100644
index 4f4e39ee3..000000000
Binary files a/glyphs/icon_down.gif and /dev/null differ
diff --git a/glyphs/icon_eye.gif b/glyphs/icon_eye.gif
deleted file mode 100644
index df4bb829e..000000000
Binary files a/glyphs/icon_eye.gif and /dev/null differ
diff --git a/glyphs/icon_left.gif b/glyphs/icon_left.gif
deleted file mode 100644
index 524226ba1..000000000
Binary files a/glyphs/icon_left.gif and /dev/null differ
diff --git a/glyphs/icon_right.gif b/glyphs/icon_right.gif
deleted file mode 100644
index 15ff3cf59..000000000
Binary files a/glyphs/icon_right.gif and /dev/null differ
diff --git a/glyphs/icon_toggle_reset.gif b/glyphs/icon_toggle_reset.gif
deleted file mode 100644
index 450bc869d..000000000
Binary files a/glyphs/icon_toggle_reset.gif and /dev/null differ
diff --git a/glyphs/icon_toggle_set.gif b/glyphs/icon_toggle_set.gif
deleted file mode 100644
index 571264c79..000000000
Binary files a/glyphs/icon_toggle_set.gif and /dev/null differ
diff --git a/glyphs/icon_up.gif b/glyphs/icon_up.gif
deleted file mode 100644
index 4e13c064f..000000000
Binary files a/glyphs/icon_up.gif and /dev/null differ
diff --git a/glyphs/icon_validate_14.gif b/glyphs/icon_validate_14.gif
deleted file mode 100644
index ccb5cabe3..000000000
Binary files a/glyphs/icon_validate_14.gif and /dev/null differ
diff --git a/glyphs/icon_warning.gif b/glyphs/icon_warning.gif
deleted file mode 100644
index 08bd4a739..000000000
Binary files a/glyphs/icon_warning.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_akroma.gif b/glyphs/nanos_badge_akroma.gif
deleted file mode 100644
index 9dfdea6ed..000000000
Binary files a/glyphs/nanos_badge_akroma.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_artis_sigma1.gif b/glyphs/nanos_badge_artis_sigma1.gif
deleted file mode 100644
index 3ef0eaa6f..000000000
Binary files a/glyphs/nanos_badge_artis_sigma1.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_artis_tau1.gif b/glyphs/nanos_badge_artis_tau1.gif
deleted file mode 100644
index 9e741b54e..000000000
Binary files a/glyphs/nanos_badge_artis_tau1.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_atheios.gif b/glyphs/nanos_badge_atheios.gif
deleted file mode 100644
index e7447fadc..000000000
Binary files a/glyphs/nanos_badge_atheios.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_callisto.gif b/glyphs/nanos_badge_callisto.gif
deleted file mode 100644
index 25a0cddfe..000000000
Binary files a/glyphs/nanos_badge_callisto.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_dexon.gif b/glyphs/nanos_badge_dexon.gif
deleted file mode 100644
index 65021cc8c..000000000
Binary files a/glyphs/nanos_badge_dexon.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_ellaism.gif b/glyphs/nanos_badge_ellaism.gif
deleted file mode 100644
index d07bad78f..000000000
Binary files a/glyphs/nanos_badge_ellaism.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_ether1.gif b/glyphs/nanos_badge_ether1.gif
deleted file mode 100644
index 776f6454b..000000000
Binary files a/glyphs/nanos_badge_ether1.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_ethereum.gif b/glyphs/nanos_badge_ethereum.gif
deleted file mode 100644
index 776f6454b..000000000
Binary files a/glyphs/nanos_badge_ethereum.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_ethereum_classic.gif b/glyphs/nanos_badge_ethereum_classic.gif
deleted file mode 100644
index 776f6454b..000000000
Binary files a/glyphs/nanos_badge_ethereum_classic.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_ethergem.gif b/glyphs/nanos_badge_ethergem.gif
deleted file mode 100644
index 19b762159..000000000
Binary files a/glyphs/nanos_badge_ethergem.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_ethersocial.gif b/glyphs/nanos_badge_ethersocial.gif
deleted file mode 100644
index 21262eba8..000000000
Binary files a/glyphs/nanos_badge_ethersocial.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_expanse.gif b/glyphs/nanos_badge_expanse.gif
deleted file mode 100644
index b1c996dba..000000000
Binary files a/glyphs/nanos_badge_expanse.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_gochain.gif b/glyphs/nanos_badge_gochain.gif
deleted file mode 100644
index 39ed2fb3f..000000000
Binary files a/glyphs/nanos_badge_gochain.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_hpb.gif b/glyphs/nanos_badge_hpb.gif
deleted file mode 100644
index ee2a1f0c8..000000000
Binary files a/glyphs/nanos_badge_hpb.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_kusd.gif b/glyphs/nanos_badge_kusd.gif
deleted file mode 100644
index b1ac932b7..000000000
Binary files a/glyphs/nanos_badge_kusd.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_mix.gif b/glyphs/nanos_badge_mix.gif
deleted file mode 100644
index 776f6454b..000000000
Binary files a/glyphs/nanos_badge_mix.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_musicoin.gif b/glyphs/nanos_badge_musicoin.gif
deleted file mode 100644
index b8288acd0..000000000
Binary files a/glyphs/nanos_badge_musicoin.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_pirl.gif b/glyphs/nanos_badge_pirl.gif
deleted file mode 100644
index ab21513c4..000000000
Binary files a/glyphs/nanos_badge_pirl.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_poa.gif b/glyphs/nanos_badge_poa.gif
deleted file mode 100644
index e45186609..000000000
Binary files a/glyphs/nanos_badge_poa.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_reosc.gif b/glyphs/nanos_badge_reosc.gif
deleted file mode 100644
index fe388baea..000000000
Binary files a/glyphs/nanos_badge_reosc.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_ropsten.gif b/glyphs/nanos_badge_ropsten.gif
deleted file mode 100644
index 776f6454b..000000000
Binary files a/glyphs/nanos_badge_ropsten.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_rsk.gif b/glyphs/nanos_badge_rsk.gif
deleted file mode 100644
index 5ca99a56e..000000000
Binary files a/glyphs/nanos_badge_rsk.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_thundercore.gif b/glyphs/nanos_badge_thundercore.gif
deleted file mode 100644
index e72367907..000000000
Binary files a/glyphs/nanos_badge_thundercore.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_tomochain.gif b/glyphs/nanos_badge_tomochain.gif
deleted file mode 100644
index f33c2ba01..000000000
Binary files a/glyphs/nanos_badge_tomochain.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_ubiq.gif b/glyphs/nanos_badge_ubiq.gif
deleted file mode 100644
index d2ce45c40..000000000
Binary files a/glyphs/nanos_badge_ubiq.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_wanchain.gif b/glyphs/nanos_badge_wanchain.gif
deleted file mode 100644
index 53bdccdde..000000000
Binary files a/glyphs/nanos_badge_wanchain.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_webchain.gif b/glyphs/nanos_badge_webchain.gif
deleted file mode 100644
index 515eed39f..000000000
Binary files a/glyphs/nanos_badge_webchain.gif and /dev/null differ
diff --git a/glyphs/stax_akroma_64px.gif b/glyphs/stax_akroma_64px.gif
new file mode 100644
index 000000000..d092851df
Binary files /dev/null and b/glyphs/stax_akroma_64px.gif differ
diff --git a/glyphs/stax_apothemnetwork_64px.gif b/glyphs/stax_apothemnetwork_64px.gif
new file mode 100644
index 000000000..974f8bb31
Binary files /dev/null and b/glyphs/stax_apothemnetwork_64px.gif differ
diff --git a/glyphs/stax_artis_sigma1_64px.gif b/glyphs/stax_artis_sigma1_64px.gif
new file mode 100644
index 000000000..05c4f221c
Binary files /dev/null and b/glyphs/stax_artis_sigma1_64px.gif differ
diff --git a/glyphs/stax_artis_tau1_64px.gif b/glyphs/stax_artis_tau1_64px.gif
new file mode 100644
index 000000000..87b527dae
Binary files /dev/null and b/glyphs/stax_artis_tau1_64px.gif differ
diff --git a/glyphs/stax_astar_64px.gif b/glyphs/stax_astar_64px.gif
new file mode 100644
index 000000000..60fb1e8fc
Binary files /dev/null and b/glyphs/stax_astar_64px.gif differ
diff --git a/glyphs/stax_atheios_64px.gif b/glyphs/stax_atheios_64px.gif
new file mode 100644
index 000000000..051e9c37e
Binary files /dev/null and b/glyphs/stax_atheios_64px.gif differ
diff --git a/glyphs/stax_bsc_64px.gif b/glyphs/stax_bsc_64px.gif
new file mode 100644
index 000000000..956f73dcc
Binary files /dev/null and b/glyphs/stax_bsc_64px.gif differ
diff --git a/glyphs/stax_bttc_64px.gif b/glyphs/stax_bttc_64px.gif
new file mode 100644
index 000000000..99e51ff01
Binary files /dev/null and b/glyphs/stax_bttc_64px.gif differ
diff --git a/glyphs/stax_callisto_64px.gif b/glyphs/stax_callisto_64px.gif
new file mode 100644
index 000000000..44a6b888a
Binary files /dev/null and b/glyphs/stax_callisto_64px.gif differ
diff --git a/glyphs/stax_conflux_espace_64px.gif b/glyphs/stax_conflux_espace_64px.gif
new file mode 100644
index 000000000..d6f790d41
Binary files /dev/null and b/glyphs/stax_conflux_espace_64px.gif differ
diff --git a/glyphs/stax_cube_64px.gif b/glyphs/stax_cube_64px.gif
new file mode 100644
index 000000000..818672285
Binary files /dev/null and b/glyphs/stax_cube_64px.gif differ
diff --git a/glyphs/stax_dexon_64px.gif b/glyphs/stax_dexon_64px.gif
new file mode 100644
index 000000000..d37f6b26b
Binary files /dev/null and b/glyphs/stax_dexon_64px.gif differ
diff --git a/glyphs/stax_ellaism_64px.gif b/glyphs/stax_ellaism_64px.gif
new file mode 100644
index 000000000..b785d4899
Binary files /dev/null and b/glyphs/stax_ellaism_64px.gif differ
diff --git a/glyphs/stax_energywebchain_64px.gif b/glyphs/stax_energywebchain_64px.gif
new file mode 100644
index 000000000..5cd4c4da1
Binary files /dev/null and b/glyphs/stax_energywebchain_64px.gif differ
diff --git a/glyphs/stax_ether1_64px.gif b/glyphs/stax_ether1_64px.gif
new file mode 100644
index 000000000..ec41146ed
Binary files /dev/null and b/glyphs/stax_ether1_64px.gif differ
diff --git a/glyphs/stax_ethereum_64px.gif b/glyphs/stax_ethereum_64px.gif
new file mode 100644
index 000000000..7cd7be3df
Binary files /dev/null and b/glyphs/stax_ethereum_64px.gif differ
diff --git a/glyphs/stax_ethereum_classic_64px.gif b/glyphs/stax_ethereum_classic_64px.gif
new file mode 100644
index 000000000..5aeed55c1
Binary files /dev/null and b/glyphs/stax_ethereum_classic_64px.gif differ
diff --git a/glyphs/stax_ethergem_64px.gif b/glyphs/stax_ethergem_64px.gif
new file mode 100644
index 000000000..8bdb8e5f1
Binary files /dev/null and b/glyphs/stax_ethergem_64px.gif differ
diff --git a/glyphs/stax_ethersocial_64px.gif b/glyphs/stax_ethersocial_64px.gif
new file mode 100644
index 000000000..530fe5540
Binary files /dev/null and b/glyphs/stax_ethersocial_64px.gif differ
diff --git a/glyphs/stax_expanse_64px.gif b/glyphs/stax_expanse_64px.gif
new file mode 100644
index 000000000..61698c8d9
Binary files /dev/null and b/glyphs/stax_expanse_64px.gif differ
diff --git a/glyphs/stax_flare_64px.gif b/glyphs/stax_flare_64px.gif
new file mode 100644
index 000000000..c834fcb36
Binary files /dev/null and b/glyphs/stax_flare_64px.gif differ
diff --git a/glyphs/stax_flare_coston_64px.gif b/glyphs/stax_flare_coston_64px.gif
new file mode 100644
index 000000000..28822f300
Binary files /dev/null and b/glyphs/stax_flare_coston_64px.gif differ
diff --git a/glyphs/stax_gochain_64px.gif b/glyphs/stax_gochain_64px.gif
new file mode 100644
index 000000000..aec56d005
Binary files /dev/null and b/glyphs/stax_gochain_64px.gif differ
diff --git a/glyphs/stax_goerli_64px.gif b/glyphs/stax_goerli_64px.gif
new file mode 100644
index 000000000..3c4839434
Binary files /dev/null and b/glyphs/stax_goerli_64px.gif differ
diff --git a/glyphs/stax_hpb_64px.gif b/glyphs/stax_hpb_64px.gif
new file mode 100644
index 000000000..392151ae6
Binary files /dev/null and b/glyphs/stax_hpb_64px.gif differ
diff --git a/glyphs/stax_id4good_64px.gif b/glyphs/stax_id4good_64px.gif
new file mode 100644
index 000000000..6d04b228f
Binary files /dev/null and b/glyphs/stax_id4good_64px.gif differ
diff --git a/glyphs/stax_kardiachain_64px.gif b/glyphs/stax_kardiachain_64px.gif
new file mode 100644
index 000000000..66b6e6fb9
Binary files /dev/null and b/glyphs/stax_kardiachain_64px.gif differ
diff --git a/glyphs/stax_kusd_64px.gif b/glyphs/stax_kusd_64px.gif
new file mode 100644
index 000000000..b18730662
Binary files /dev/null and b/glyphs/stax_kusd_64px.gif differ
diff --git a/glyphs/stax_meter_64px.gif b/glyphs/stax_meter_64px.gif
new file mode 100644
index 000000000..ee0804bc3
Binary files /dev/null and b/glyphs/stax_meter_64px.gif differ
diff --git a/glyphs/stax_mix_64px.gif b/glyphs/stax_mix_64px.gif
new file mode 100644
index 000000000..e3a3e570a
Binary files /dev/null and b/glyphs/stax_mix_64px.gif differ
diff --git a/glyphs/stax_moonbeam_64px.gif b/glyphs/stax_moonbeam_64px.gif
new file mode 100644
index 000000000..e8485ee55
Binary files /dev/null and b/glyphs/stax_moonbeam_64px.gif differ
diff --git a/glyphs/stax_moonriver_64px.gif b/glyphs/stax_moonriver_64px.gif
new file mode 100644
index 000000000..180985709
Binary files /dev/null and b/glyphs/stax_moonriver_64px.gif differ
diff --git a/glyphs/stax_multivac_64px.gif b/glyphs/stax_multivac_64px.gif
new file mode 100644
index 000000000..e3ea71657
Binary files /dev/null and b/glyphs/stax_multivac_64px.gif differ
diff --git a/glyphs/stax_musicoin_64px.gif b/glyphs/stax_musicoin_64px.gif
new file mode 100644
index 000000000..d9dce6c3f
Binary files /dev/null and b/glyphs/stax_musicoin_64px.gif differ
diff --git a/glyphs/stax_oasys_64px.gif b/glyphs/stax_oasys_64px.gif
new file mode 100644
index 000000000..81c0e5fe8
Binary files /dev/null and b/glyphs/stax_oasys_64px.gif differ
diff --git a/glyphs/stax_okc_64px.gif b/glyphs/stax_okc_64px.gif
new file mode 100644
index 000000000..f377521af
Binary files /dev/null and b/glyphs/stax_okc_64px.gif differ
diff --git a/glyphs/stax_pirl_64px.gif b/glyphs/stax_pirl_64px.gif
new file mode 100644
index 000000000..7c9733164
Binary files /dev/null and b/glyphs/stax_pirl_64px.gif differ
diff --git a/glyphs/stax_poa_64px.gif b/glyphs/stax_poa_64px.gif
new file mode 100644
index 000000000..d857c1781
Binary files /dev/null and b/glyphs/stax_poa_64px.gif differ
diff --git a/glyphs/stax_polygon_64px.gif b/glyphs/stax_polygon_64px.gif
new file mode 100644
index 000000000..40b99e10b
Binary files /dev/null and b/glyphs/stax_polygon_64px.gif differ
diff --git a/glyphs/stax_reosc_64px.gif b/glyphs/stax_reosc_64px.gif
new file mode 100644
index 000000000..fa727e370
Binary files /dev/null and b/glyphs/stax_reosc_64px.gif differ
diff --git a/glyphs/stax_ropsten_64px.gif b/glyphs/stax_ropsten_64px.gif
new file mode 100644
index 000000000..6025affd8
Binary files /dev/null and b/glyphs/stax_ropsten_64px.gif differ
diff --git a/glyphs/stax_rsk_64px.gif b/glyphs/stax_rsk_64px.gif
new file mode 100644
index 000000000..5e25ff6b2
Binary files /dev/null and b/glyphs/stax_rsk_64px.gif differ
diff --git a/glyphs/stax_shiden_64px.gif b/glyphs/stax_shiden_64px.gif
new file mode 100644
index 000000000..6bbe136ca
Binary files /dev/null and b/glyphs/stax_shiden_64px.gif differ
diff --git a/glyphs/stax_shyft_64px.gif b/glyphs/stax_shyft_64px.gif
new file mode 100644
index 000000000..78a7ea9c8
Binary files /dev/null and b/glyphs/stax_shyft_64px.gif differ
diff --git a/glyphs/stax_songbird_64px.gif b/glyphs/stax_songbird_64px.gif
new file mode 100644
index 000000000..e635b9569
Binary files /dev/null and b/glyphs/stax_songbird_64px.gif differ
diff --git a/glyphs/stax_tecracoin_64px.gif b/glyphs/stax_tecracoin_64px.gif
new file mode 100644
index 000000000..4fa9b491c
Binary files /dev/null and b/glyphs/stax_tecracoin_64px.gif differ
diff --git a/glyphs/stax_thundercore_64px.gif b/glyphs/stax_thundercore_64px.gif
new file mode 100644
index 000000000..76134be81
Binary files /dev/null and b/glyphs/stax_thundercore_64px.gif differ
diff --git a/glyphs/stax_tobalaba_64px.gif b/glyphs/stax_tobalaba_64px.gif
new file mode 100644
index 000000000..0125e6b45
Binary files /dev/null and b/glyphs/stax_tobalaba_64px.gif differ
diff --git a/glyphs/stax_tomochain_64px.gif b/glyphs/stax_tomochain_64px.gif
new file mode 100644
index 000000000..6abef3351
Binary files /dev/null and b/glyphs/stax_tomochain_64px.gif differ
diff --git a/glyphs/stax_ubiq_64px.gif b/glyphs/stax_ubiq_64px.gif
new file mode 100644
index 000000000..740b7e99c
Binary files /dev/null and b/glyphs/stax_ubiq_64px.gif differ
diff --git a/glyphs/stax_volta_64px.gif b/glyphs/stax_volta_64px.gif
new file mode 100644
index 000000000..83cfb91c4
Binary files /dev/null and b/glyphs/stax_volta_64px.gif differ
diff --git a/glyphs/stax_wanchain_64px.gif b/glyphs/stax_wanchain_64px.gif
new file mode 100644
index 000000000..27a5582da
Binary files /dev/null and b/glyphs/stax_wanchain_64px.gif differ
diff --git a/glyphs/stax_webchain_64px.gif b/glyphs/stax_webchain_64px.gif
new file mode 100644
index 000000000..585832f1d
Binary files /dev/null and b/glyphs/stax_webchain_64px.gif differ
diff --git a/glyphs/stax_wethio_64px.gif b/glyphs/stax_wethio_64px.gif
new file mode 100644
index 000000000..8a66b1209
Binary files /dev/null and b/glyphs/stax_wethio_64px.gif differ
diff --git a/glyphs/stax_xdcnetwork_64px.gif b/glyphs/stax_xdcnetwork_64px.gif
new file mode 100644
index 000000000..b990ab31e
Binary files /dev/null and b/glyphs/stax_xdcnetwork_64px.gif differ
diff --git a/icons/akroma.png b/icons/akroma.png
deleted file mode 100644
index 22baa92a1..000000000
Binary files a/icons/akroma.png and /dev/null differ
diff --git a/icons/artis_sigma1.png b/icons/artis_sigma1.png
deleted file mode 100644
index f6b47b129..000000000
Binary files a/icons/artis_sigma1.png and /dev/null differ
diff --git a/icons/artis_tau1.png b/icons/artis_tau1.png
deleted file mode 100644
index 388009a32..000000000
Binary files a/icons/artis_tau1.png and /dev/null differ
diff --git a/icons/atheios.png b/icons/atheios.png
deleted file mode 100644
index 22af8d272..000000000
Binary files a/icons/atheios.png and /dev/null differ
diff --git a/icons/blue_app_akroma.gif b/icons/blue_app_akroma.gif
deleted file mode 100644
index 12c9cd215..000000000
Binary files a/icons/blue_app_akroma.gif and /dev/null differ
diff --git a/icons/blue_app_artis_sigma1.gif b/icons/blue_app_artis_sigma1.gif
deleted file mode 100644
index 8c47bf3a5..000000000
Binary files a/icons/blue_app_artis_sigma1.gif and /dev/null differ
diff --git a/icons/blue_app_artis_tau1.gif b/icons/blue_app_artis_tau1.gif
deleted file mode 100644
index 3dfdf0629..000000000
Binary files a/icons/blue_app_artis_tau1.gif and /dev/null differ
diff --git a/icons/blue_app_atheios.gif b/icons/blue_app_atheios.gif
deleted file mode 100644
index 916915645..000000000
Binary files a/icons/blue_app_atheios.gif and /dev/null differ
diff --git a/icons/blue_app_callisto.gif b/icons/blue_app_callisto.gif
deleted file mode 100644
index 162765a35..000000000
Binary files a/icons/blue_app_callisto.gif and /dev/null differ
diff --git a/icons/blue_app_dexon.gif b/icons/blue_app_dexon.gif
deleted file mode 100644
index 3f51c6bc5..000000000
Binary files a/icons/blue_app_dexon.gif and /dev/null differ
diff --git a/icons/blue_app_ellaism.gif b/icons/blue_app_ellaism.gif
deleted file mode 100644
index 0936f88ba..000000000
Binary files a/icons/blue_app_ellaism.gif and /dev/null differ
diff --git a/icons/blue_app_ether1.gif b/icons/blue_app_ether1.gif
deleted file mode 100644
index 1592686a1..000000000
Binary files a/icons/blue_app_ether1.gif and /dev/null differ
diff --git a/icons/blue_app_ethereum.gif b/icons/blue_app_ethereum.gif
deleted file mode 100644
index c3d5c4e1d..000000000
Binary files a/icons/blue_app_ethereum.gif and /dev/null differ
diff --git a/icons/blue_app_ethereum_classic.gif b/icons/blue_app_ethereum_classic.gif
deleted file mode 100644
index dceaa1510..000000000
Binary files a/icons/blue_app_ethereum_classic.gif and /dev/null differ
diff --git a/icons/blue_app_ethergem.gif b/icons/blue_app_ethergem.gif
deleted file mode 100644
index 539f76ebd..000000000
Binary files a/icons/blue_app_ethergem.gif and /dev/null differ
diff --git a/icons/blue_app_ethersocial.gif b/icons/blue_app_ethersocial.gif
deleted file mode 100644
index 2df10f438..000000000
Binary files a/icons/blue_app_ethersocial.gif and /dev/null differ
diff --git a/icons/blue_app_ewc.gif b/icons/blue_app_ewc.gif
deleted file mode 100644
index d1c438fce..000000000
Binary files a/icons/blue_app_ewc.gif and /dev/null differ
diff --git a/icons/blue_app_expanse.gif b/icons/blue_app_expanse.gif
deleted file mode 100644
index 82660042d..000000000
Binary files a/icons/blue_app_expanse.gif and /dev/null differ
diff --git a/icons/blue_app_gochain.gif b/icons/blue_app_gochain.gif
deleted file mode 100644
index 50ae2bee9..000000000
Binary files a/icons/blue_app_gochain.gif and /dev/null differ
diff --git a/icons/blue_app_goerli.gif b/icons/blue_app_goerli.gif
deleted file mode 100644
index c3d5c4e1d..000000000
Binary files a/icons/blue_app_goerli.gif and /dev/null differ
diff --git a/icons/blue_app_hpb.gif b/icons/blue_app_hpb.gif
deleted file mode 100644
index d15b589b0..000000000
Binary files a/icons/blue_app_hpb.gif and /dev/null differ
diff --git a/icons/blue_app_kusd.gif b/icons/blue_app_kusd.gif
deleted file mode 100644
index d4c5496a1..000000000
Binary files a/icons/blue_app_kusd.gif and /dev/null differ
diff --git a/icons/blue_app_mix.gif b/icons/blue_app_mix.gif
deleted file mode 100644
index 38cdca838..000000000
Binary files a/icons/blue_app_mix.gif and /dev/null differ
diff --git a/icons/blue_app_musicoin.gif b/icons/blue_app_musicoin.gif
deleted file mode 100644
index 42f818510..000000000
Binary files a/icons/blue_app_musicoin.gif and /dev/null differ
diff --git a/icons/blue_app_pirl.gif b/icons/blue_app_pirl.gif
deleted file mode 100644
index a6824ae7d..000000000
Binary files a/icons/blue_app_pirl.gif and /dev/null differ
diff --git a/icons/blue_app_poa.gif b/icons/blue_app_poa.gif
deleted file mode 100644
index 679fc6661..000000000
Binary files a/icons/blue_app_poa.gif and /dev/null differ
diff --git a/icons/blue_app_reosc.gif b/icons/blue_app_reosc.gif
deleted file mode 100644
index aaf46981d..000000000
Binary files a/icons/blue_app_reosc.gif and /dev/null differ
diff --git a/icons/blue_app_ropsten.gif b/icons/blue_app_ropsten.gif
deleted file mode 100644
index c3d5c4e1d..000000000
Binary files a/icons/blue_app_ropsten.gif and /dev/null differ
diff --git a/icons/blue_app_rsk.gif b/icons/blue_app_rsk.gif
deleted file mode 100644
index 7cd4fa050..000000000
Binary files a/icons/blue_app_rsk.gif and /dev/null differ
diff --git a/icons/blue_app_theta.gif b/icons/blue_app_theta.gif
deleted file mode 100644
index 5056f1b45..000000000
Binary files a/icons/blue_app_theta.gif and /dev/null differ
diff --git a/icons/blue_app_thundercore.gif b/icons/blue_app_thundercore.gif
deleted file mode 100644
index bfa6ba571..000000000
Binary files a/icons/blue_app_thundercore.gif and /dev/null differ
diff --git a/icons/blue_app_tobalaba.gif b/icons/blue_app_tobalaba.gif
deleted file mode 100644
index d1c438fce..000000000
Binary files a/icons/blue_app_tobalaba.gif and /dev/null differ
diff --git a/icons/blue_app_tomochain.gif b/icons/blue_app_tomochain.gif
deleted file mode 100644
index 6ef28c768..000000000
Binary files a/icons/blue_app_tomochain.gif and /dev/null differ
diff --git a/icons/blue_app_ubiq.gif b/icons/blue_app_ubiq.gif
deleted file mode 100644
index 6ac116acf..000000000
Binary files a/icons/blue_app_ubiq.gif and /dev/null differ
diff --git a/icons/blue_app_volta.gif b/icons/blue_app_volta.gif
deleted file mode 100644
index d1c438fce..000000000
Binary files a/icons/blue_app_volta.gif and /dev/null differ
diff --git a/icons/blue_app_wanchain.gif b/icons/blue_app_wanchain.gif
deleted file mode 100644
index 0332113a8..000000000
Binary files a/icons/blue_app_wanchain.gif and /dev/null differ
diff --git a/icons/blue_app_webchain.gif b/icons/blue_app_webchain.gif
deleted file mode 100644
index 50c5b1f99..000000000
Binary files a/icons/blue_app_webchain.gif and /dev/null differ
diff --git a/icons/blue_badge_thundercore.gif b/icons/blue_badge_thundercore.gif
deleted file mode 100644
index a31bbe32d..000000000
Binary files a/icons/blue_badge_thundercore.gif and /dev/null differ
diff --git a/icons/blue_badge_tomochain.gif b/icons/blue_badge_tomochain.gif
deleted file mode 100644
index cf7c4b568..000000000
Binary files a/icons/blue_badge_tomochain.gif and /dev/null differ
diff --git a/icons/callisto.png b/icons/callisto.png
deleted file mode 100644
index 3319589e7..000000000
Binary files a/icons/callisto.png and /dev/null differ
diff --git a/icons/dexon.png b/icons/dexon.png
deleted file mode 100644
index c6a934a8f..000000000
Binary files a/icons/dexon.png and /dev/null differ
diff --git a/icons/ellaism.png b/icons/ellaism.png
deleted file mode 100644
index 9ea64d0bd..000000000
Binary files a/icons/ellaism.png and /dev/null differ
diff --git a/icons/ether1.png b/icons/ether1.png
deleted file mode 100644
index 68aec970e..000000000
Binary files a/icons/ether1.png and /dev/null differ
diff --git a/icons/ethereum.png b/icons/ethereum.png
deleted file mode 100755
index 60e111ce0..000000000
Binary files a/icons/ethereum.png and /dev/null differ
diff --git a/icons/ethereum_classic.png b/icons/ethereum_classic.png
deleted file mode 100755
index 6807e1493..000000000
Binary files a/icons/ethereum_classic.png and /dev/null differ
diff --git a/icons/ethergem.png b/icons/ethergem.png
deleted file mode 100644
index ad9608503..000000000
Binary files a/icons/ethergem.png and /dev/null differ
diff --git a/icons/ethersocial.png b/icons/ethersocial.png
deleted file mode 100644
index 5fd623f3f..000000000
Binary files a/icons/ethersocial.png and /dev/null differ
diff --git a/icons/ewc.png b/icons/ewc.png
deleted file mode 100644
index 5bda6b796..000000000
Binary files a/icons/ewc.png and /dev/null differ
diff --git a/icons/expanse.png b/icons/expanse.png
deleted file mode 100755
index 27f275cc3..000000000
Binary files a/icons/expanse.png and /dev/null differ
diff --git a/icons/flare.png b/icons/flare.png
deleted file mode 100644
index 57d5519e6..000000000
Binary files a/icons/flare.png and /dev/null differ
diff --git a/icons/flare_coston.png b/icons/flare_coston.png
deleted file mode 100644
index b732549b2..000000000
Binary files a/icons/flare_coston.png and /dev/null differ
diff --git a/icons/gochain.png b/icons/gochain.png
deleted file mode 100644
index 67154f805..000000000
Binary files a/icons/gochain.png and /dev/null differ
diff --git a/icons/goerli.png b/icons/goerli.png
deleted file mode 100755
index 60e111ce0..000000000
Binary files a/icons/goerli.png and /dev/null differ
diff --git a/icons/hpb.png b/icons/hpb.png
deleted file mode 100644
index 39d1d419d..000000000
Binary files a/icons/hpb.png and /dev/null differ
diff --git a/icons/icon_split.gif b/icons/icon_split.gif
deleted file mode 100644
index 0ab40011f..000000000
Binary files a/icons/icon_split.gif and /dev/null differ
diff --git a/icons/kusd.png b/icons/kusd.png
deleted file mode 100644
index e69b3fc3a..000000000
Binary files a/icons/kusd.png and /dev/null differ
diff --git a/icons/mix.png b/icons/mix.png
deleted file mode 100644
index 02af27ecf..000000000
Binary files a/icons/mix.png and /dev/null differ
diff --git a/icons/musicoin.png b/icons/musicoin.png
deleted file mode 100644
index 2d6ec90d1..000000000
Binary files a/icons/musicoin.png and /dev/null differ
diff --git a/icons/nanos_app_tecracoin.gif b/icons/nanos_app_tecracoin.gif
old mode 100755
new mode 100644
diff --git a/icons/nanox_app_tecracoin.gif b/icons/nanox_app_tecracoin.gif
old mode 100755
new mode 100644
diff --git a/icons/pirl.png b/icons/pirl.png
deleted file mode 100644
index 9ba9202fc..000000000
Binary files a/icons/pirl.png and /dev/null differ
diff --git a/icons/poa.png b/icons/poa.png
deleted file mode 100644
index 1443ae071..000000000
Binary files a/icons/poa.png and /dev/null differ
diff --git a/icons/reosc.png b/icons/reosc.png
deleted file mode 100644
index c38bbc324..000000000
Binary files a/icons/reosc.png and /dev/null differ
diff --git a/icons/ropsten.png b/icons/ropsten.png
deleted file mode 100755
index 60e111ce0..000000000
Binary files a/icons/ropsten.png and /dev/null differ
diff --git a/icons/rsk.png b/icons/rsk.png
deleted file mode 100644
index 2e8a9b4dd..000000000
Binary files a/icons/rsk.png and /dev/null differ
diff --git a/icons/songbird.png b/icons/songbird.png
deleted file mode 100644
index 0fd35ec03..000000000
Binary files a/icons/songbird.png and /dev/null differ
diff --git a/icons/stax_app_akroma.gif b/icons/stax_app_akroma.gif
new file mode 100644
index 000000000..79768660e
Binary files /dev/null and b/icons/stax_app_akroma.gif differ
diff --git a/icons/stax_app_apothemnetwork.gif b/icons/stax_app_apothemnetwork.gif
new file mode 100644
index 000000000..381f07069
Binary files /dev/null and b/icons/stax_app_apothemnetwork.gif differ
diff --git a/icons/stax_app_artis_sigma1.gif b/icons/stax_app_artis_sigma1.gif
new file mode 100644
index 000000000..8d769dba2
Binary files /dev/null and b/icons/stax_app_artis_sigma1.gif differ
diff --git a/icons/stax_app_artis_tau1.gif b/icons/stax_app_artis_tau1.gif
new file mode 100644
index 000000000..555be4a6d
Binary files /dev/null and b/icons/stax_app_artis_tau1.gif differ
diff --git a/icons/stax_app_astar.gif b/icons/stax_app_astar.gif
new file mode 100644
index 000000000..458e51910
Binary files /dev/null and b/icons/stax_app_astar.gif differ
diff --git a/icons/stax_app_atheios.gif b/icons/stax_app_atheios.gif
new file mode 100644
index 000000000..10a3e3b3b
Binary files /dev/null and b/icons/stax_app_atheios.gif differ
diff --git a/icons/stax_app_bsc.gif b/icons/stax_app_bsc.gif
new file mode 100644
index 000000000..311d31a04
Binary files /dev/null and b/icons/stax_app_bsc.gif differ
diff --git a/icons/stax_app_bttc.gif b/icons/stax_app_bttc.gif
new file mode 100644
index 000000000..cc8a3f986
Binary files /dev/null and b/icons/stax_app_bttc.gif differ
diff --git a/icons/stax_app_callisto.gif b/icons/stax_app_callisto.gif
new file mode 100644
index 000000000..890dd9f34
Binary files /dev/null and b/icons/stax_app_callisto.gif differ
diff --git a/icons/stax_app_conflux_espace.gif b/icons/stax_app_conflux_espace.gif
new file mode 100644
index 000000000..e39f4425b
Binary files /dev/null and b/icons/stax_app_conflux_espace.gif differ
diff --git a/icons/stax_app_cube.gif b/icons/stax_app_cube.gif
new file mode 100644
index 000000000..1a5b3c8e6
Binary files /dev/null and b/icons/stax_app_cube.gif differ
diff --git a/icons/stax_app_dexon.gif b/icons/stax_app_dexon.gif
new file mode 100644
index 000000000..692537fdd
Binary files /dev/null and b/icons/stax_app_dexon.gif differ
diff --git a/icons/stax_app_ellaism.gif b/icons/stax_app_ellaism.gif
new file mode 100644
index 000000000..ac5ef8500
Binary files /dev/null and b/icons/stax_app_ellaism.gif differ
diff --git a/icons/stax_app_energywebchain.gif b/icons/stax_app_energywebchain.gif
new file mode 100644
index 000000000..3f8a57438
Binary files /dev/null and b/icons/stax_app_energywebchain.gif differ
diff --git a/icons/stax_app_ether1.gif b/icons/stax_app_ether1.gif
new file mode 100644
index 000000000..1f4698843
Binary files /dev/null and b/icons/stax_app_ether1.gif differ
diff --git a/icons/stax_app_ethereum.gif b/icons/stax_app_ethereum.gif
new file mode 100644
index 000000000..c1d6d3401
Binary files /dev/null and b/icons/stax_app_ethereum.gif differ
diff --git a/icons/stax_app_ethereum_classic.gif b/icons/stax_app_ethereum_classic.gif
new file mode 100644
index 000000000..10a661d87
Binary files /dev/null and b/icons/stax_app_ethereum_classic.gif differ
diff --git a/icons/stax_app_ethergem.gif b/icons/stax_app_ethergem.gif
new file mode 100644
index 000000000..0ed7b1cf9
Binary files /dev/null and b/icons/stax_app_ethergem.gif differ
diff --git a/icons/stax_app_ethersocial.gif b/icons/stax_app_ethersocial.gif
new file mode 100644
index 000000000..e8fc4dd4a
Binary files /dev/null and b/icons/stax_app_ethersocial.gif differ
diff --git a/icons/stax_app_expanse.gif b/icons/stax_app_expanse.gif
new file mode 100644
index 000000000..9dfd8705f
Binary files /dev/null and b/icons/stax_app_expanse.gif differ
diff --git a/icons/stax_app_flare.gif b/icons/stax_app_flare.gif
new file mode 100644
index 000000000..4d1a0f875
Binary files /dev/null and b/icons/stax_app_flare.gif differ
diff --git a/icons/stax_app_flare_coston.gif b/icons/stax_app_flare_coston.gif
new file mode 100644
index 000000000..2f77deea1
Binary files /dev/null and b/icons/stax_app_flare_coston.gif differ
diff --git a/icons/stax_app_gochain.gif b/icons/stax_app_gochain.gif
new file mode 100644
index 000000000..04bb08df6
Binary files /dev/null and b/icons/stax_app_gochain.gif differ
diff --git a/icons/stax_app_goerli.gif b/icons/stax_app_goerli.gif
new file mode 100644
index 000000000..95c819d26
Binary files /dev/null and b/icons/stax_app_goerli.gif differ
diff --git a/icons/stax_app_hpb.gif b/icons/stax_app_hpb.gif
new file mode 100644
index 000000000..4c4e50d16
Binary files /dev/null and b/icons/stax_app_hpb.gif differ
diff --git a/icons/stax_app_id4good.gif b/icons/stax_app_id4good.gif
new file mode 100644
index 000000000..ae3fae4a7
Binary files /dev/null and b/icons/stax_app_id4good.gif differ
diff --git a/icons/stax_app_kardiachain.gif b/icons/stax_app_kardiachain.gif
new file mode 100644
index 000000000..0c092ffa2
Binary files /dev/null and b/icons/stax_app_kardiachain.gif differ
diff --git a/icons/stax_app_kusd.gif b/icons/stax_app_kusd.gif
new file mode 100644
index 000000000..18b1a1c5e
Binary files /dev/null and b/icons/stax_app_kusd.gif differ
diff --git a/icons/stax_app_meter.gif b/icons/stax_app_meter.gif
new file mode 100644
index 000000000..d07813d1a
Binary files /dev/null and b/icons/stax_app_meter.gif differ
diff --git a/icons/stax_app_mix.gif b/icons/stax_app_mix.gif
new file mode 100644
index 000000000..f82aafcb9
Binary files /dev/null and b/icons/stax_app_mix.gif differ
diff --git a/icons/stax_app_moonbeam.gif b/icons/stax_app_moonbeam.gif
new file mode 100644
index 000000000..c8d2c9b0b
Binary files /dev/null and b/icons/stax_app_moonbeam.gif differ
diff --git a/icons/stax_app_moonriver.gif b/icons/stax_app_moonriver.gif
new file mode 100644
index 000000000..69466a7a5
Binary files /dev/null and b/icons/stax_app_moonriver.gif differ
diff --git a/icons/stax_app_multivac.gif b/icons/stax_app_multivac.gif
new file mode 100644
index 000000000..ad33059e7
Binary files /dev/null and b/icons/stax_app_multivac.gif differ
diff --git a/icons/stax_app_musicoin.gif b/icons/stax_app_musicoin.gif
new file mode 100644
index 000000000..eced2ed72
Binary files /dev/null and b/icons/stax_app_musicoin.gif differ
diff --git a/icons/stax_app_oasys.gif b/icons/stax_app_oasys.gif
new file mode 100644
index 000000000..83995c697
Binary files /dev/null and b/icons/stax_app_oasys.gif differ
diff --git a/icons/stax_app_okc.gif b/icons/stax_app_okc.gif
new file mode 100644
index 000000000..38cfa3cc3
Binary files /dev/null and b/icons/stax_app_okc.gif differ
diff --git a/icons/stax_app_pirl.gif b/icons/stax_app_pirl.gif
new file mode 100644
index 000000000..6ac7154d3
Binary files /dev/null and b/icons/stax_app_pirl.gif differ
diff --git a/icons/stax_app_poa.gif b/icons/stax_app_poa.gif
new file mode 100644
index 000000000..afa1186ba
Binary files /dev/null and b/icons/stax_app_poa.gif differ
diff --git a/icons/stax_app_polygon.gif b/icons/stax_app_polygon.gif
new file mode 100644
index 000000000..eba2eaad3
Binary files /dev/null and b/icons/stax_app_polygon.gif differ
diff --git a/icons/stax_app_reosc.gif b/icons/stax_app_reosc.gif
new file mode 100644
index 000000000..50fe3fba6
Binary files /dev/null and b/icons/stax_app_reosc.gif differ
diff --git a/icons/stax_app_ropsten.gif b/icons/stax_app_ropsten.gif
new file mode 100644
index 000000000..4c7a5a0e7
Binary files /dev/null and b/icons/stax_app_ropsten.gif differ
diff --git a/icons/stax_app_rsk.gif b/icons/stax_app_rsk.gif
new file mode 100644
index 000000000..a576134bc
Binary files /dev/null and b/icons/stax_app_rsk.gif differ
diff --git a/icons/stax_app_shiden.gif b/icons/stax_app_shiden.gif
new file mode 100644
index 000000000..132230948
Binary files /dev/null and b/icons/stax_app_shiden.gif differ
diff --git a/icons/stax_app_shyft.gif b/icons/stax_app_shyft.gif
new file mode 100644
index 000000000..0741eddac
Binary files /dev/null and b/icons/stax_app_shyft.gif differ
diff --git a/icons/stax_app_songbird.gif b/icons/stax_app_songbird.gif
new file mode 100644
index 000000000..811d72ac1
Binary files /dev/null and b/icons/stax_app_songbird.gif differ
diff --git a/icons/stax_app_tecracoin.gif b/icons/stax_app_tecracoin.gif
new file mode 100644
index 000000000..a1ccb2d47
Binary files /dev/null and b/icons/stax_app_tecracoin.gif differ
diff --git a/icons/stax_app_thundercore.gif b/icons/stax_app_thundercore.gif
new file mode 100644
index 000000000..4d730a167
Binary files /dev/null and b/icons/stax_app_thundercore.gif differ
diff --git a/icons/stax_app_tobalaba.gif b/icons/stax_app_tobalaba.gif
new file mode 100644
index 000000000..cd3e9464e
Binary files /dev/null and b/icons/stax_app_tobalaba.gif differ
diff --git a/icons/stax_app_tomochain.gif b/icons/stax_app_tomochain.gif
new file mode 100644
index 000000000..eb8d01a1a
Binary files /dev/null and b/icons/stax_app_tomochain.gif differ
diff --git a/icons/stax_app_ubiq.gif b/icons/stax_app_ubiq.gif
new file mode 100644
index 000000000..afd0577ad
Binary files /dev/null and b/icons/stax_app_ubiq.gif differ
diff --git a/icons/stax_app_volta.gif b/icons/stax_app_volta.gif
new file mode 100644
index 000000000..ea4c02447
Binary files /dev/null and b/icons/stax_app_volta.gif differ
diff --git a/icons/stax_app_wanchain.gif b/icons/stax_app_wanchain.gif
new file mode 100644
index 000000000..cf628048c
Binary files /dev/null and b/icons/stax_app_wanchain.gif differ
diff --git a/icons/stax_app_webchain.gif b/icons/stax_app_webchain.gif
new file mode 100644
index 000000000..3deecb3ff
Binary files /dev/null and b/icons/stax_app_webchain.gif differ
diff --git a/icons/stax_app_wethio.gif b/icons/stax_app_wethio.gif
new file mode 100644
index 000000000..4b540302e
Binary files /dev/null and b/icons/stax_app_wethio.gif differ
diff --git a/icons/stax_app_xdcnetwork.gif b/icons/stax_app_xdcnetwork.gif
new file mode 100644
index 000000000..2cd15b212
Binary files /dev/null and b/icons/stax_app_xdcnetwork.gif differ
diff --git a/icons/thundercore.png b/icons/thundercore.png
deleted file mode 100644
index 49758acfc..000000000
Binary files a/icons/thundercore.png and /dev/null differ
diff --git a/icons/tobalaba.png b/icons/tobalaba.png
deleted file mode 100644
index 5bda6b796..000000000
Binary files a/icons/tobalaba.png and /dev/null differ
diff --git a/icons/tomochain.png b/icons/tomochain.png
deleted file mode 100644
index 9e20e2c34..000000000
Binary files a/icons/tomochain.png and /dev/null differ
diff --git a/icons/ubiq.png b/icons/ubiq.png
deleted file mode 100755
index b702a7b28..000000000
Binary files a/icons/ubiq.png and /dev/null differ
diff --git a/icons/volta.png b/icons/volta.png
deleted file mode 100644
index 5bda6b796..000000000
Binary files a/icons/volta.png and /dev/null differ
diff --git a/icons/wanchain.png b/icons/wanchain.png
deleted file mode 100755
index a73f62bb8..000000000
Binary files a/icons/wanchain.png and /dev/null differ
diff --git a/icons/webchain.png b/icons/webchain.png
deleted file mode 100644
index be97f3cec..000000000
Binary files a/icons/webchain.png and /dev/null differ
diff --git a/src/common_ui.h b/src/common_ui.h
index 9b2b0dc88..e14f57baf 100644
--- a/src/common_ui.h
+++ b/src/common_ui.h
@@ -9,7 +9,6 @@ void ui_display_public_eth2(void);
 void ui_display_privacy_public_key(void);
 void ui_display_privacy_shared_secret(void);
 void ui_display_public_key(void);
-void ui_display_sign(void);
 void ui_sign_712_v0(void);
 void ui_display_stark_public(void);
 void ui_confirm_selector(void);
diff --git a/src/eth_plugin_handler.c b/src/eth_plugin_handler.c
index 3aa6883ef..bb73e9e1f 100644
--- a/src/eth_plugin_handler.c
+++ b/src/eth_plugin_handler.c
@@ -47,6 +47,8 @@ void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
                                           uint32_t titleLength,
                                           char *msg,
                                           uint32_t msgLength) {
+    uint64_t chain_id;
+
     memset((uint8_t *) queryContractUI, 0, sizeof(ethQueryContractUI_t));
 
     // If no extra information was found, set the pointer to NULL
@@ -64,7 +66,8 @@ void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
     }
 
     queryContractUI->screenIndex = screenIndex;
-    strlcpy(queryContractUI->network_ticker, get_network_ticker(), MAX_TICKER_LEN);
+    chain_id = get_tx_chain_id();
+    strlcpy(queryContractUI->network_ticker, get_displayable_ticker(&chain_id), MAX_TICKER_LEN);
     queryContractUI->title = title;
     queryContractUI->titleLength = titleLength;
     queryContractUI->msg = msg;
@@ -149,7 +152,7 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
     }
 
     // Do not handle a plugin if running in swap mode
-    if (called_from_swap && (contractAddress != NULL)) {
+    if (G_called_from_swap && (contractAddress != NULL)) {
         PRINTF("eth_plug_init aborted in swap mode\n");
         return 0;
     }
diff --git a/src/eth_plugin_internal.h b/src/eth_plugin_internal.h
index 692c9b609..2d2ca0369 100644
--- a/src/eth_plugin_internal.h
+++ b/src/eth_plugin_internal.h
@@ -7,7 +7,6 @@
 
 #define SELECTOR_SIZE    4
 #define PARAMETER_LENGTH 32
-#define RUN_APPLICATION  1
 
 void copy_address(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size);
 
diff --git a/src/handle_swap_sign_transaction.c b/src/handle_swap_sign_transaction.c
index 75e4d3a8e..604b8a26c 100644
--- a/src/handle_swap_sign_transaction.c
+++ b/src/handle_swap_sign_transaction.c
@@ -1,8 +1,15 @@
 #include "os_io_seproxyhal.h"
+#include "os.h"
 #include "ux.h"
 #include "handle_swap_sign_transaction.h"
 #include "shared_context.h"
 #include "utils.h"
+#ifdef HAVE_NBGL
+#include "nbgl_use_case.h"
+#endif  // HAVE_NBGL
+
+// Save the BSS address where we will write the return value when finished
+static uint8_t* G_swap_sign_return_value_address;
 
 bool copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params,
                                  chain_config_t* config) {
@@ -45,14 +52,30 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
                    stack_data.maxFee,
                    sizeof(stack_data.maxFee));
 
+    // Full reset the global variables
+    os_explicit_zero_BSS_segment();
+    // Keep the address at which we'll reply the signing status
+    G_swap_sign_return_value_address = &sign_transaction_params->result;
+    // Commit the values read from exchange to the clean global space
+
     memcpy(&strings.common, &stack_data, sizeof(stack_data));
     return true;
 }
 
+void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_success) {
+    *G_swap_sign_return_value_address = is_success;
+    os_lib_end();
+}
+
 void handle_swap_sign_transaction(chain_config_t* config) {
+    UX_INIT();
+#ifdef HAVE_NBGL
+    nbgl_useCaseSpinner("Signing");
+#endif  // HAVE_NBGL
+
     chainConfig = config;
     reset_app_context();
-    called_from_swap = true;
+    G_called_from_swap = true;
     io_seproxyhal_init();
 
     if (N_storage.initialized != 0x01) {
@@ -65,18 +88,15 @@ void handle_swap_sign_transaction(chain_config_t* config) {
         nvm_write((void*) &N_storage, (void*) &storage, sizeof(internalStorage_t));
     }
 
-    UX_INIT();
     USB_power(0);
     USB_power(1);
     // ui_idle();
     PRINTF("USB power ON/OFF\n");
-#ifdef TARGET_NANOX
+#ifdef HAVE_BLE
     // grab the current plane mode setting
     G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
-#endif  // TARGET_NANOX
-#ifdef HAVE_BLE
     BLE_power(0, NULL);
-    BLE_power(1, "Nano X");
+    BLE_power(1, NULL);
 #endif  // HAVE_BLE
     app_main();
 }
diff --git a/src/handle_swap_sign_transaction.h b/src/handle_swap_sign_transaction.h
index 21b52c356..d34a6d860 100644
--- a/src/handle_swap_sign_transaction.h
+++ b/src/handle_swap_sign_transaction.h
@@ -1,5 +1,4 @@
-#ifndef _HANDLE_SWAP_SIGN_TRANSACTION_H_
-#define _HANDLE_SWAP_SIGN_TRANSACTION_H_
+#pragma once
 
 #include "swap_lib_calls.h"
 #include "chainConfig.h"
@@ -9,4 +8,4 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
 
 void handle_swap_sign_transaction(chain_config_t* config);
 
-#endif  // _HANDLE_SWAP_SIGN_TRANSACTION_H_
\ No newline at end of file
+void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_success);
diff --git a/src/main.c b/src/main.c
index a483bf401..3399b8614 100644
--- a/src/main.c
+++ b/src/main.c
@@ -52,7 +52,7 @@ cx_sha3_t global_sha3;
 
 uint8_t appState;
 uint16_t apdu_response_code;
-bool called_from_swap;
+bool G_called_from_swap;
 pluginType_t pluginType;
 #ifdef HAVE_STARKWARE
 bool quantumSet;
@@ -69,12 +69,15 @@ bolos_ux_params_t G_ux_params;
 
 const internalStorage_t N_storage_real;
 
-chain_config_t *chainConfig;
+#ifdef HAVE_NBGL
+caller_app_t *caller_app = NULL;
+#endif
+chain_config_t *chainConfig = NULL;
 
 void reset_app_context() {
     // PRINTF("!!RESET_APP_CONTEXT\n");
     appState = APP_STATE_IDLE;
-    called_from_swap = false;
+    G_called_from_swap = false;
     pluginType = OLD_INTERNAL;
 #ifdef HAVE_STARKWARE
     quantumSet = false;
@@ -877,9 +880,11 @@ void app_main(void) {
 }
 
 // override point, but nothing more to do
+#ifdef HAVE_BAGL
 void io_seproxyhal_display(const bagl_element_t *element) {
     io_seproxyhal_display_default((bagl_element_t *) element);
 }
+#endif
 
 unsigned char io_event(__attribute__((unused)) unsigned char channel) {
     // nothing done with the event, throw an error on the transport layer if
@@ -890,10 +895,11 @@ unsigned char io_event(__attribute__((unused)) unsigned char channel) {
         case SEPROXYHAL_TAG_FINGER_EVENT:
             UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
             break;
-
+#ifdef HAVE_BAGL
         case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT:
             UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
             break;
+#endif  // HAVE_BAGL
 
         case SEPROXYHAL_TAG_STATUS_EVENT:
             if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID &&
@@ -901,22 +907,23 @@ unsigned char io_event(__attribute__((unused)) unsigned char channel) {
                   SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
                 THROW(EXCEPTION_IO_RESET);
             }
-            // no break is intentional
+            __attribute__((fallthrough));
         default:
             UX_DEFAULT_EVENT();
             break;
 
         case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
+#ifdef HAVE_BAGL
             UX_DISPLAYED_EVENT({});
+#endif  // HAVE_BAGL
+#ifdef HAVE_NBGL
+            UX_DEFAULT_EVENT();
+#endif  // HAVE_NBGL
             break;
 
-#if 0
-    case SEPROXYHAL_TAG_TICKER_EVENT:
-        UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer,
-        {
-        });
-        break;
-#endif
+        case SEPROXYHAL_TAG_TICKER_EVENT:
+            UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {});
+            break;
     }
 
     // close the event if not done previously (by a display or whatever)
@@ -946,14 +953,27 @@ void init_coin_config(chain_config_t *coin_config) {
     coin_config->kind = CHAIN_KIND;
 }
 
-void coin_main(chain_config_t *coin_config) {
+void coin_main(libargs_t *args) {
     chain_config_t config;
-    if (coin_config == NULL) {
+    if (args) {
+        if (args->chain_config != NULL) {
+            chainConfig = args->chain_config;
+        }
+#ifdef HAVE_NBGL
+        if ((caller_app = args->caller_app) != NULL) {
+            if (chainConfig != NULL) {
+                caller_app->type = CALLER_TYPE_CLONE;
+            } else {
+                caller_app->type = CALLER_TYPE_PLUGIN;
+            }
+        }
+#endif
+    }
+    if (chainConfig == NULL) {
         init_coin_config(&config);
         chainConfig = &config;
-    } else {
-        chainConfig = coin_config;
     }
+
     reset_app_context();
     tmpCtx.transactionContext.currentItemIndex = 0;
 
@@ -964,10 +984,10 @@ void coin_main(chain_config_t *coin_config) {
             TRY {
                 io_seproxyhal_init();
 
-#ifdef TARGET_NANOX
+#ifdef HAVE_BLE
                 // grab the current plane mode setting
                 G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
-#endif  // TARGET_NANOX
+#endif  // HAVE_BLE
 
                 if (!N_storage.initialized) {
                     internalStorage_t storage;
@@ -995,7 +1015,7 @@ void coin_main(chain_config_t *coin_config) {
 
 #ifdef HAVE_BLE
                 BLE_power(0, NULL);
-                BLE_power(1, "Nano X");
+                BLE_power(1, NULL);
 #endif  // HAVE_BLE
 
 #ifdef HAVE_DOMAIN_NAME
@@ -1022,18 +1042,7 @@ void coin_main(chain_config_t *coin_config) {
     app_exit();
 }
 
-struct libargs_s {
-    unsigned int id;
-    unsigned int command;
-    chain_config_t *chain_config;
-    union {
-        check_address_parameters_t *check_address;
-        create_transaction_parameters_t *create_transaction;
-        get_printable_amount_parameters_t *get_printable_amount;
-    };
-};
-
-static void library_main_helper(struct libargs_s *args) {
+static void library_main_helper(libargs_t *args) {
     check_api_level(CX_COMPAT_APILEVEL);
     PRINTF("Inside a library \n");
     switch (args->command) {
@@ -1061,13 +1070,13 @@ static void library_main_helper(struct libargs_s *args) {
     }
 }
 
-void library_main(struct libargs_s *args) {
+void library_main(libargs_t *args) {
     chain_config_t coin_config;
     if (args->chain_config == NULL) {
         init_coin_config(&coin_config);
         args->chain_config = &coin_config;
     }
-    bool end = false;
+    volatile bool end = false;
     /* This loop ensures that library_main_helper and os_lib_end are called
      * within a try context, even if an exception is thrown */
     while (1) {
@@ -1093,6 +1102,7 @@ __attribute__((section(".boot"))) int main(int arg0) {
             unsigned int libcall_params[5];
             chain_config_t local_chainConfig;
             init_coin_config(&local_chainConfig);
+
             PRINTF("Hello from Eth-clone\n");
             check_api_level(CX_COMPAT_APILEVEL);
             // delegate to Ethereum app/lib
@@ -1100,7 +1110,22 @@ __attribute__((section(".boot"))) int main(int arg0) {
             libcall_params[1] = 0x100;
             libcall_params[2] = RUN_APPLICATION;
             libcall_params[3] = (unsigned int) &local_chainConfig;
-            libcall_params[4] = 0;
+#ifdef HAVE_NBGL
+            const char app_name[] = APPNAME;
+            caller_app_t capp;
+            nbgl_icon_details_t icon_details;
+            uint8_t bitmap[sizeof(ICONBITMAP)];
+
+            memcpy(&icon_details, &ICONGLYPH, sizeof(ICONGLYPH));
+            memcpy(&bitmap, &ICONBITMAP, sizeof(bitmap));
+            icon_details.bitmap = (const uint8_t *) bitmap;
+            capp.name = app_name;
+            capp.icon = &icon_details;
+            libcall_params[4] = (unsigned int) &capp;
+#else
+            libcall_params[4] = NULL;
+#endif  // HAVE_NBGL
+
             if (arg0) {
                 // call as a library
                 libcall_params[2] = ((unsigned int *) arg0)[1];
@@ -1132,7 +1157,7 @@ __attribute__((section(".boot"))) int main(int arg0) {
         return 0;
     }
 
-    struct libargs_s *args = (struct libargs_s *) arg0;
+    libargs_t *args = (libargs_t *) arg0;
     if (args->id != 0x100) {
         app_exit();
         return 0;
@@ -1140,7 +1165,7 @@ __attribute__((section(".boot"))) int main(int arg0) {
     switch (args->command) {
         case RUN_APPLICATION:
             // called as ethereum from altcoin or plugin
-            coin_main(args->chain_config);
+            coin_main(args);
             break;
         default:
             // called as ethereum or altcoin library
diff --git a/src/shared_context.h b/src/shared_context.h
index ce907ddd9..f83320cb5 100644
--- a/src/shared_context.h
+++ b/src/shared_context.h
@@ -7,6 +7,9 @@
 #include "tokens.h"
 #include "chainConfig.h"
 #include "nft.h"
+#ifdef HAVE_NBGL
+#include "nbgl_types.h"
+#endif
 
 #define MAX_BIP32_PATH 10
 
@@ -210,7 +213,7 @@ extern strings_t strings;
 extern cx_sha3_t global_sha3;
 extern const internalStorage_t N_storage_real;
 
-extern bool called_from_swap;
+extern bool G_called_from_swap;
 
 typedef enum {
     EXTERNAL,     //  External plugin, set by setExternalPlugin.
@@ -221,6 +224,16 @@ typedef enum {
 
 extern pluginType_t pluginType;
 
+typedef enum { CALLER_TYPE_CLONE, CALLER_TYPE_PLUGIN } e_caller_type;
+
+typedef struct caller_app_t {
+    const char *name;
+#ifdef HAVE_NBGL
+    const nbgl_icon_details_t *icon;
+#endif
+    char type;  // does not have to be set by the caller app
+} caller_app_t;
+
 extern uint8_t appState;
 #ifdef HAVE_STARKWARE
 extern bool quantumSet;
@@ -229,6 +242,8 @@ extern bool quantumSet;
 extern uint32_t eth2WithdrawalIndex;
 #endif
 
+extern caller_app_t *caller_app;
+
 void reset_app_context(void);
 const uint8_t *parseBip32(const uint8_t *dataBuffer, uint8_t *dataLength, bip32_path_t *bip32);
 
diff --git a/src/swap_lib_calls.h b/src/swap_lib_calls.h
index 9bdb11522..287034707 100644
--- a/src/swap_lib_calls.h
+++ b/src/swap_lib_calls.h
@@ -1,7 +1,15 @@
-#ifndef _SWAP_LIB_CALLS_H_
-#define _SWAP_LIB_CALLS_H_
+#pragma once
+
+/* This file is the shared API between Exchange and the apps started in Library mode for Exchange
+ *
+ * DO NOT MODIFY THIS FILE IN APPLICATIONS OTHER THAN EXCHANGE
+ * On modification in Exchange, forward the changes to all applications supporting Exchange
+ */
 
 #include "stdbool.h"
+#include "chainConfig.h"
+#include "shared_context.h"
+#include "stdint.h"
 
 #define RUN_APPLICATION 1
 
@@ -11,19 +19,27 @@
 
 #define GET_PRINTABLE_AMOUNT 4
 
+/*
+ * Amounts are stored as bytes, with a max size of 16 (see protobuf
+ * specifications). Max 16B integer is 340282366920938463463374607431768211455
+ * in decimal, which is a 32-long char string.
+ * The printable amount also contains spaces, the ticker symbol (with variable
+ * size, up to 12 in Ethereum for instance) and a terminating null byte, so 50
+ * bytes total should be a fair maximum.
+ */
 #define MAX_PRINTABLE_AMOUNT_SIZE 50
 
 // structure that should be send to specific coin application to get address
 typedef struct check_address_parameters_s {
     // IN
-    const unsigned char* const coin_configuration;
-    const unsigned char coin_configuration_length;
+    uint8_t *coin_configuration;
+    uint8_t coin_configuration_length;
     // serialized path, segwit, version prefix, hash used, dictionary etc.
-    // fields and serialization format depends on spesific coin app
-    const unsigned char* const address_parameters;
-    const unsigned char address_parameters_length;
-    const char* const address_to_check;
-    const char* const extra_id_to_check;
+    // fields and serialization format depends on specific coin app
+    uint8_t *address_parameters;
+    uint8_t address_parameters_length;
+    char *address_to_check;
+    char *extra_id_to_check;
     // OUT
     int result;
 } check_address_parameters_t;
@@ -31,25 +47,37 @@ typedef struct check_address_parameters_s {
 // structure that should be send to specific coin application to get printable amount
 typedef struct get_printable_amount_parameters_s {
     // IN
-    const unsigned char* const coin_configuration;
-    const unsigned char coin_configuration_length;
-    const unsigned char* const amount;
-    const unsigned char amount_length;
-    const bool is_fee;
+    uint8_t *coin_configuration;
+    uint8_t coin_configuration_length;
+    uint8_t *amount;
+    uint8_t amount_length;
+    bool is_fee;
     // OUT
     char printable_amount[MAX_PRINTABLE_AMOUNT_SIZE];
-    // int result;
 } get_printable_amount_parameters_t;
 
 typedef struct create_transaction_parameters_s {
-    const unsigned char* const coin_configuration;
-    const unsigned char coin_configuration_length;
-    const unsigned char* const amount;
-    const unsigned char amount_length;
-    const unsigned char* const fee_amount;
-    const unsigned char fee_amount_length;
-    const char* const destination_address;
-    const char* const destination_address_extra_id;
+    // IN
+    uint8_t *coin_configuration;
+    uint8_t coin_configuration_length;
+    uint8_t *amount;
+    uint8_t amount_length;
+    uint8_t *fee_amount;
+    uint8_t fee_amount_length;
+    char *destination_address;
+    char *destination_address_extra_id;
+    // OUT
+    uint8_t result;
 } create_transaction_parameters_t;
 
-#endif  // _SWAP_LIB_CALLS_H_
+typedef struct libargs_s {
+    unsigned int id;
+    unsigned int command;
+    chain_config_t *chain_config;
+    union {
+        check_address_parameters_t *check_address;
+        create_transaction_parameters_t *create_transaction;
+        get_printable_amount_parameters_t *get_printable_amount;
+        caller_app_t *caller_app;
+    };
+} libargs_t;
diff --git a/src/tokens.c b/src/tokens.c
index e17e482c8..a513758bd 100644
--- a/src/tokens.c
+++ b/src/tokens.c
@@ -24,36 +24,36 @@ const tokenDefinition_t TOKENS_EXTRA[NUM_TOKENS_EXTRA] = {
     // Ropsten DeversiFi tokens
     {{0x4c, 0x5f, 0x66, 0x59, 0x61, 0x97, 0xa8, 0x6f, 0xb3, 0x0a,
       0x24, 0x35, 0xe2, 0xef, 0x4d, 0xdc, 0xb3, 0x93, 0x42, 0xc9},
-     "tUSDT ",
+     "tUSDT",
      6},
     {{0x1c, 0x0f, 0x17, 0x43, 0x67, 0x40, 0xbf, 0xb9, 0x2c, 0x10,
       0x70, 0xee, 0x86, 0x32, 0x2d, 0xe8, 0x90, 0x83, 0x7c, 0x6a},
-     "tUSDT ",
+     "tUSDT",
      6},
     {{0xcd, 0x07, 0x7a, 0xbe, 0xdd, 0x83, 0x1a, 0x34, 0x43, 0xff,
       0xbe, 0x24, 0xfb, 0x76, 0x66, 0x1b, 0xbb, 0x17, 0xeb, 0x69},
-     "tZRX ",
+     "tZRX",
      18},
     {{0x40, 0xd8, 0x97, 0x85, 0x00, 0xbf, 0x68, 0x32, 0x4a, 0x51,
       0x53, 0x3c, 0xd6, 0xa2, 0x1e, 0x3e, 0x59, 0xbe, 0x32, 0x4a},
-     "tBTC ",
+     "tBTC",
      18},
     // Goerli DeversiFi tokens
     {{0xd9, 0x97, 0xa8, 0x63, 0x46, 0xe7, 0x65, 0x18, 0xe6, 0x92,
       0x25, 0x56, 0xf3, 0x4d, 0x76, 0x61, 0x30, 0xc0, 0xbb, 0xfd},
-     "tUSDT ",
+     "tUSDT",
      6},
     {{0xc1, 0xd5, 0x79, 0xeb, 0xff, 0x7c, 0x0f, 0x6c, 0xfd, 0x9a,
       0xd5, 0xfb, 0x26, 0x7f, 0xec, 0x73, 0xbe, 0x70, 0xc8, 0xf7},
-     "tBTC ",
+     "tBTC",
      18},
     {{0xa8, 0xf3, 0x14, 0x4f, 0xea, 0x2c, 0x37, 0x5a, 0xd0, 0x58,
       0xec, 0x12, 0x09, 0x9a, 0x5a, 0x21, 0xa2, 0x6f, 0xe9, 0x96},
-     "tDVF ",
+     "tDVF",
      18},
     {{0x4c, 0xda, 0xbe, 0xc1, 0x2a, 0x39, 0x7f, 0xb6, 0xef, 0xaf,
       0x46, 0x13, 0xd5, 0xdf, 0xd7, 0x9b, 0x30, 0x9a, 0xe9, 0xfa},
-     "tXDVF ",
+     "tXDVF",
      18},
 
 };
@@ -69,11 +69,11 @@ const tokenDefinition_t TOKENS_EXTRA[NUM_TOKENS_EXTRA] = {
 const tokenDefinition_t const TOKENS_ETHEREUM[NUM_TOKENS_ETHEREUM] = {
     {{0xdb, 0x25, 0xf2, 0x11, 0xab, 0x05, 0xb1, 0xc9, 0x7d, 0x59,
       0x55, 0x16, 0xf4, 0x57, 0x94, 0x52, 0x8a, 0x80, 0x7a, 0xd8},
-     "EURS ",
+     "EURS",
      2},
     {{0xa7, 0x44, 0x76, 0x44, 0x31, 0x19, 0xA9, 0x42, 0xdE, 0x49,
       0x85, 0x90, 0xFe, 0x1f, 0x24, 0x54, 0xd7, 0xD4, 0xaC, 0x0d},
-     "GNT ",
+     "GNT",
      18},
 };
 
@@ -89,19 +89,19 @@ const tokenDefinition_t const TOKENS_ELLAISM[NUM_TOKENS_ELLAISM] = {
 const tokenDefinition_t const TOKENS_ETHEREUM_CLASSIC[NUM_TOKENS_ETHEREUM_CLASSIC] = {
     {{0x6F, 0x6D, 0xEb, 0x5d, 0xb0, 0xC4, 0x99, 0x4A, 0x82, 0x83,
       0xA0, 0x1D, 0x6C, 0xFe, 0xEB, 0x27, 0xFc, 0x3b, 0xBe, 0x9C},
-     "Smart ",
+     "Smart",
      0},
     {{0x08, 0x5f, 0xb4, 0xf2, 0x40, 0x31, 0xea, 0xed, 0xbc, 0x2b,
       0x61, 0x1a, 0xa5, 0x28, 0xf2, 0x23, 0x43, 0xeb, 0x52, 0xdb},
-     "BEC ",
+     "BEC",
      8},
     {{0x5a, 0xce, 0x17, 0xf8, 0x7c, 0x73, 0x91, 0xe5, 0x79, 0x2a,
       0x76, 0x83, 0x06, 0x9a, 0x80, 0x25, 0xb8, 0x3b, 0xbd, 0x85},
-     "PLAY ",
+     "PLAY",
      0},
     {{0x6A, 0xDa, 0x6F, 0x48, 0xC8, 0x15, 0x68, 0x95, 0x02, 0xC4,
       0x3e, 0xC1, 0xa5, 0x9F, 0x1b, 0x5D, 0xD3, 0xC0, 0x4E, 0x1F},
-     "UNV ",
+     "UNV",
      18},
 };
 
@@ -118,27 +118,27 @@ const tokenDefinition_t const TOKENS_RSK[NUM_TOKENS_RSK] = {};
 const tokenDefinition_t const TOKENS_UBIQ[NUM_TOKENS_UBIQ] = {
     {{0xd2, 0x45, 0x20, 0x7c, 0xfb, 0xf6, 0xeb, 0x6f, 0x34, 0x97,
       0x0d, 0xb2, 0xa8, 0x07, 0xab, 0x1d, 0x17, 0x8f, 0xde, 0x6c},
-     "APX ",
+     "APX",
      8},
     {{0xff, 0x3b, 0xf0, 0x57, 0xad, 0xf3, 0xb0, 0xe0, 0x15, 0xb6,
       0x46, 0x53, 0x31, 0xa6, 0x23, 0x6e, 0x55, 0x68, 0x82, 0x74},
-     "BEER ",
+     "BEER",
      0},
     {{0x08, 0x53, 0x3d, 0x6a, 0x06, 0xce, 0x36, 0x52, 0x98, 0xb1,
       0x2e, 0xf9, 0x2e, 0xb4, 0x07, 0xcb, 0xa8, 0xaa, 0x82, 0x73},
-     "CEFS ",
+     "CEFS",
      8},
     {{0x94, 0xad, 0x7e, 0x41, 0xc1, 0xd4, 0x40, 0x22, 0xc4, 0xf4,
       0x7c, 0xb1, 0xba, 0x01, 0x9f, 0xd1, 0xa0, 0x22, 0xc5, 0x36},
-     "DOT ",
+     "DOT",
      8},
     {{0x4b, 0x48, 0x99, 0xa1, 0x0f, 0x3e, 0x50, 0x7d, 0xb2, 0x07,
       0xb0, 0xee, 0x24, 0x26, 0x02, 0x9e, 0xfa, 0x16, 0x8a, 0x67},
-     "QWARK ",
+     "QWARK",
      8},
     {{0x5e, 0x17, 0x15, 0xbb, 0x79, 0x80, 0x5b, 0xd6, 0x72, 0x72,
       0x97, 0x60, 0xb3, 0xf7, 0xf3, 0x4d, 0x6f, 0x48, 0x50, 0x98},
-     "RICKS ",
+     "RICKS",
      8},
 };
 
diff --git a/src/ui_callbacks.h b/src/ui_callbacks.h
index 2035c27a9..041f7173e 100644
--- a/src/ui_callbacks.h
+++ b/src/ui_callbacks.h
@@ -4,6 +4,10 @@
 #include "shared_context.h"
 #include "ux.h"
 
+#ifdef HAVE_NBGL
+typedef int bagl_element_t;
+#endif
+
 unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e);
 unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e);
 unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e);
diff --git a/src_bagl/ui_flow_signTx.c b/src_bagl/ui_flow_signTx.c
index 2b5592207..5d8e7b394 100644
--- a/src_bagl/ui_flow_signTx.c
+++ b/src_bagl/ui_flow_signTx.c
@@ -7,6 +7,7 @@
 #include "eth_plugin_handler.h"
 #include "ui_plugin.h"
 #include "common_ui.h"
+#include "ethUtils.h"
 #include "plugins.h"
 #include "domain_name.h"
 #include "ui_domain_name.h"
@@ -220,7 +221,7 @@ void ux_approve_tx(bool fromPlugin) {
         // We're in a regular transaction, just show the amount and the address
         ux_approval_tx_flow[step++] = &ux_approval_amount_step;
 #ifdef HAVE_DOMAIN_NAME
-        uint64_t chain_id = get_chain_id();
+        uint64_t chain_id = get_tx_chain_id();
         if (has_domain_name(&chain_id, tmpContent.txContent.destination)) {
             ux_approval_tx_flow[step++] = &ux_domain_name_step;
             if (N_storage.verbose_domain_name) {
@@ -238,7 +239,7 @@ void ux_approve_tx(bool fromPlugin) {
         ux_approval_tx_flow[step++] = &ux_approval_nonce_step;
     }
 
-    uint64_t chain_id = get_chain_id();
+    uint64_t chain_id = get_tx_chain_id();
     if (chainConfig->chainId == ETHEREUM_MAINNET_CHAINID && chain_id != chainConfig->chainId) {
         ux_approval_tx_flow[step++] = &ux_approval_network_step;
     }
diff --git a/src_common/ethUtils.c b/src_common/ethUtils.c
index 4dd0e6a57..e66e0d2e5 100644
--- a/src_common/ethUtils.c
+++ b/src_common/ethUtils.c
@@ -27,9 +27,12 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "shared_context.h"
+#include "utils.h"
 #include "ethUtils.h"
 #include "chainConfig.h"
 #include "ethUstream.h"
+#include "network.h"
 
 bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid) {
     if (*buffer <= 0x7f) {
@@ -301,3 +304,32 @@ bool adjustDecimals(const char *src,
     }
     return true;
 }
+
+// Returns the chain ID. Defaults to 0 if txType was not found (For TX).
+uint64_t get_tx_chain_id(void) {
+    uint64_t chain_id = 0;
+
+    switch (txContext.txType) {
+        case LEGACY:
+            chain_id = u64_from_BE(txContext.content->v, txContext.content->vLength);
+            break;
+        case EIP2930:
+        case EIP1559:
+            chain_id = u64_from_BE(tmpContent.txContent.chainID.value,
+                                   tmpContent.txContent.chainID.length);
+            break;
+        default:
+            PRINTF("Txtype `%d` not supported while generating chainID\n", txContext.txType);
+            break;
+    }
+    return chain_id;
+}
+
+const char *get_displayable_ticker(const uint64_t *chain_id) {
+    const char *ticker = get_network_ticker_from_chain_id(chain_id);
+
+    if (ticker == NULL) {
+        ticker = chainConfig->coinName;
+    }
+    return ticker;
+}
diff --git a/src_common/ethUtils.h b/src_common/ethUtils.h
index 9722e2c43..870253351 100644
--- a/src_common/ethUtils.h
+++ b/src_common/ethUtils.h
@@ -84,6 +84,10 @@ static __attribute__((no_instrument_function)) inline int ismaxint(uint8_t *buf,
     return 1;
 }
 
+uint64_t get_tx_chain_id(void);
+
+const char *get_displayable_ticker(const uint64_t *chain_id);
+
 static const char HEXDIGITS[] = "0123456789abcdef";
 
 #endif  // _ETHUTILS_H_
diff --git a/src_common/network.c b/src_common/network.c
index f0dc4d1e5..8c0d238a6 100644
--- a/src_common/network.c
+++ b/src_common/network.c
@@ -1,11 +1,13 @@
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
 #include <string.h>
+#include "os_utils.h"
+#include "os_pic.h"
 #include "network.h"
-#include "os.h"
-#include "shared_context.h"
-#include "utils.h"
+
+typedef struct network_info_s {
+    const char *name;
+    const char *ticker;
+    uint64_t chain_id;
+} network_info_t;
 
 // Mappping of chain ids to networks.
 static const network_info_t NETWORK_MAPPING[] = {
@@ -14,9 +16,11 @@ static const network_info_t NETWORK_MAPPING[] = {
     {.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 = 42, .name = "LUKSO", .ticker = "LYX"},
+    {.chain_id = 4201, .name = "LUKSO Testnet", .ticker = "LYXt"},
     {.chain_id = 56, .name = "BSC", .ticker = "BNB"},
-    {.chain_id = 100, .name = "xDai", .ticker = "xDAI"},
+    {.chain_id = 100, .name = "Gnosis", .ticker = "xDAI"},
+    {.chain_id = 10200, .name = "Chiado", .ticker = "xDAI"},
     {.chain_id = 137, .name = "Polygon", .ticker = "MATIC"},
     {.chain_id = 250, .name = "Fantom", .ticker = "FTM"},
     {.chain_id = 42161, .name = "Arbitrum", .ticker = "ETH"},
@@ -62,51 +66,45 @@ static const network_info_t NETWORK_MAPPING[] = {
     {.chain_id = 106, .name = "Velas EVM", .ticker = "VLX"},
     {.chain_id = 288, .name = "Boba Network", .ticker = "ETH"},
     {.chain_id = 39797, .name = "Energi", .ticker = "NRG"},
-    {.chain_id = 248, .name = "Oasys", .ticker = "OAS"}};
-
-uint64_t get_chain_id(void) {
-    uint64_t chain_id = 0;
-
-    switch (txContext.txType) {
-        case LEGACY:
-            chain_id = u64_from_BE(txContext.content->v, txContext.content->vLength);
-            break;
-        case EIP2930:
-        case EIP1559:
-            chain_id = u64_from_BE(tmpContent.txContent.chainID.value,
-                                   tmpContent.txContent.chainID.length);
-            break;
-        default:
-            PRINTF("Txtype `%d` not supported while generating chainID\n", txContext.txType);
-            break;
-    }
-    return chain_id;
-}
+    {.chain_id = 369, .name = "PulseChain", .ticker = "PLS"},
+    {.chain_id = 245022926, .name = "Neon EVM Devnet", .ticker = "NEON"},
+    {.chain_id = 245022934, .name = "Neon EVM Mainnet", .ticker = "NEON"},
+    {.chain_id = 4919, .name = "Venidium", .ticker = "XVM"},
+    {.chain_id = 40, .name = "Telos EVM Mainnet", .ticker = "TLOS"},
+    {.chain_id = 196, .name = "OKBChain Mainnet", .ticker = "OKB"},
+    {.chain_id = 248, .name = "Oasys", .ticker = "OAS"},
+    {.chain_id = 1101, .name = "Polygon zkEVM", .ticker = "ETH"},
+    {.chain_id = 8453, .name = "Base", .ticker = "ETH"},
+    {.chain_id = 58008, .name = "Sepolia", .ticker = "ETH"},
+};
 
-const network_info_t *get_network(void) {
-    uint64_t chain_id = get_chain_id();
-    for (size_t i = 0; i < sizeof(NETWORK_MAPPING) / sizeof(*NETWORK_MAPPING); i++) {
-        if (NETWORK_MAPPING[i].chain_id == chain_id) {
-            return (const network_info_t *) PIC(&NETWORK_MAPPING[i]);
+static const network_info_t *get_network_from_chain_id(const uint64_t *chain_id) {
+    for (size_t i = 0; i < ARRAYLEN(NETWORK_MAPPING); i++) {
+        if (NETWORK_MAPPING[i].chain_id == *chain_id) {
+            return (const network_info_t *) &NETWORK_MAPPING[i];
         }
     }
     return NULL;
 }
 
-const char *get_network_name(void) {
-    const network_info_t *network = get_network();
-    if (network == NULL) {
+const char *get_network_name_from_chain_id(const uint64_t *chain_id) {
+    const network_info_t *net = get_network_from_chain_id(chain_id);
+
+    if (net == NULL) {
         return NULL;
-    } else {
-        return (const char *) PIC(network->name);
     }
+    return PIC(net->name);
 }
 
-const char *get_network_ticker(void) {
-    const network_info_t *network = get_network();
-    if (network == NULL) {
-        return chainConfig->coinName;
-    } else {
-        return (char *) PIC(network->ticker);
+const char *get_network_ticker_from_chain_id(const uint64_t *chain_id) {
+    const network_info_t *net = get_network_from_chain_id(chain_id);
+
+    if (net == NULL) {
+        return NULL;
     }
+    return PIC(net->ticker);
+}
+
+bool chain_is_ethereum_compatible(const uint64_t *chain_id) {
+    return get_network_from_chain_id(chain_id) != NULL;
 }
diff --git a/src_common/network.h b/src_common/network.h
index b9ce7f31a..8361bcb9a 100644
--- a/src_common/network.h
+++ b/src_common/network.h
@@ -2,22 +2,11 @@
 #define _NETWORK_H_
 
 #include <stdint.h>
-#include "tokens.h"
-#include "shared_context.h"
+#include <stdbool.h>
 
-typedef struct network_info_s {
-    const char *name;
-    const char *ticker;
-    uint64_t chain_id;
-} network_info_t;
+const char *get_network_name_from_chain_id(const uint64_t *chain_id);
+const char *get_network_ticker_from_chain_id(const uint64_t *chain_id);
 
-// Returns the current chain id. Defaults to 0 if txType was not found.
-uint64_t get_chain_id(void);
-// Returns a pointer to the network struct, or NULL if there is none.
-const network_info_t *get_network(void);
-// Returns a pointer to the network name, or NULL if there is none.
-const char *get_network_name(void);
-// Returns a pointer to the network ticker, or chainConfig->coinName if there is none.
-const char *get_network_ticker(void);
+bool chain_is_ethereum_compatible(const uint64_t *chain_id);
 
 #endif  // _NETWORK_H_
diff --git a/src_features/getEth2PublicKey/cmd_getEth2PublicKey.c b/src_features/getEth2PublicKey/cmd_getEth2PublicKey.c
index 853d834fe..b1b38d5f1 100644
--- a/src_features/getEth2PublicKey/cmd_getEth2PublicKey.c
+++ b/src_features/getEth2PublicKey/cmd_getEth2PublicKey.c
@@ -49,7 +49,7 @@ void handleGetEth2PublicKey(uint8_t p1,
                             unsigned int *tx) {
     bip32_path_t bip32;
 
-    if (!called_from_swap) {
+    if (!G_called_from_swap) {
         reset_app_context();
     }
     if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
diff --git a/src_features/getPublicKey/cmd_getPublicKey.c b/src_features/getPublicKey/cmd_getPublicKey.c
index 07bab1df0..bc8bac6ce 100644
--- a/src_features/getPublicKey/cmd_getPublicKey.c
+++ b/src_features/getPublicKey/cmd_getPublicKey.c
@@ -16,7 +16,7 @@ void handleGetPublicKey(uint8_t p1,
     bip32_path_t bip32;
     cx_ecfp_private_key_t privateKey;
 
-    if (!called_from_swap) {
+    if (!G_called_from_swap) {
         reset_app_context();
     }
 
diff --git a/src_features/provideDomainName/cmd_provide_domain_name.c b/src_features/provideDomainName/cmd_provide_domain_name.c
index 0d0849f26..e1d14a49c 100644
--- a/src_features/provideDomainName/cmd_provide_domain_name.c
+++ b/src_features/provideDomainName/cmd_provide_domain_name.c
@@ -10,6 +10,7 @@
 #include "challenge.h"
 #include "mem.h"
 #include "hash_bytes.h"
+#include "network.h"
 
 static const uint8_t DOMAIN_NAME_PUB_KEY[] = {
 #ifdef HAVE_DOMAIN_NAME_TEST_KEY
@@ -124,8 +125,8 @@ bool has_domain_name(const uint64_t *chain_id, const uint8_t *addr) {
     bool ret = false;
 
     if (g_domain_name_info.valid) {
-        // TODO: Remove once other domain name providers are supported
-        if ((*chain_id == ETHEREUM_MAINNET_CHAINID) &&
+        // Check if chain ID is known to be Ethereum-compatible (same derivation path)
+        if ((chain_is_ethereum_compatible(chain_id)) &&
             (memcmp(addr, g_domain_name_info.addr, ADDRESS_LENGTH) == 0)) {
             ret = true;
         }
@@ -478,7 +479,7 @@ static bool parse_der_value(const s_tlv_payload *payload, size_t *offset, uint32
             if ((*offset + byte_length) > payload->size) {
                 PRINTF("TLV payload too small for DER encoded value\n");
             } else {
-                if (byte_length > sizeof(buf)) {
+                if (byte_length > sizeof(buf) || byte_length == 0) {
                     PRINTF("Unexpectedly long DER-encoded value (%u bytes)\n", byte_length);
                 } else {
                     memset(buf, 0, (sizeof(buf) - byte_length));
diff --git a/src_features/signMessageEIP712/commands_712.c b/src_features/signMessageEIP712/commands_712.c
index 7810b9335..a1cc45f9a 100644
--- a/src_features/signMessageEIP712/commands_712.c
+++ b/src_features/signMessageEIP712/commands_712.c
@@ -13,7 +13,8 @@
 #include "schema_hash.h"
 #include "filtering.h"
 #include "common_712.h"
-#include "ethUtils.h"  // allzeroes
+#include "ethUtils.h"   // allzeroes
+#include "common_ui.h"  // ui_idle
 
 /**
  * Send the response to the previous APDU command
@@ -38,6 +39,7 @@ void handle_eip712_return_code(bool success) {
 
     if (!success) {
         eip712_context_deinit();
+        ui_idle();
     }
 }
 
diff --git a/src_features/signMessageEIP712/context_712.c b/src_features/signMessageEIP712/context_712.c
index 82abd0935..57d5be6dd 100644
--- a/src_features/signMessageEIP712/context_712.c
+++ b/src_features/signMessageEIP712/context_712.c
@@ -72,7 +72,6 @@ void eip712_context_deinit(void) {
     mem_reset();
     eip712_context = NULL;
     reset_app_context();
-    ui_idle();
 }
 
 #endif
diff --git a/src_features/signMessageEIP712/path.c b/src_features/signMessageEIP712/path.c
index ec95242c8..621d11dc5 100644
--- a/src_features/signMessageEIP712/path.c
+++ b/src_features/signMessageEIP712/path.c
@@ -143,14 +143,18 @@ static cx_sha3_t *get_last_hash_ctx(void) {
  * Finalize the last hashing context
  *
  * @param[out] hash pointer to buffer where the hash will be stored
+ * @return whether there was anything hashed at this depth
  */
-static void finalize_hash_depth(uint8_t *hash) {
+static bool finalize_hash_depth(uint8_t *hash) {
     const cx_sha3_t *hash_ctx;
+    size_t hashed_bytes;
 
     hash_ctx = get_last_hash_ctx();
+    hashed_bytes = hash_ctx->blen;
     // finalize hash
     cx_hash((cx_hash_t *) hash_ctx, CX_LAST, NULL, 0, hash, KECCAK256_HASH_BYTESIZE);
     mem_dealloc(sizeof(*hash_ctx));  // remove hash context
+    return hashed_bytes > 0;
 }
 
 /**
@@ -192,6 +196,7 @@ static bool push_new_hash_depth(bool init) {
  */
 static bool path_depth_list_pop(void) {
     uint8_t hash[KECCAK256_HASH_BYTESIZE];
+    bool to_feed;
 
     if (path_struct == NULL) {
         return false;
@@ -201,9 +206,11 @@ static bool path_depth_list_pop(void) {
     }
     path_struct->depth_count -= 1;
 
-    finalize_hash_depth(hash);
+    to_feed = finalize_hash_depth(hash);
     if (path_struct->depth_count > 0) {
-        feed_last_hash_depth(hash);
+        if (to_feed) {
+            feed_last_hash_depth(hash);
+        }
     } else {
         switch (path_struct->root_type) {
             case ROOT_DOMAIN:
@@ -261,7 +268,7 @@ static bool array_depth_list_pop(void) {
         return false;
     }
 
-    finalize_hash_depth(hash);
+    finalize_hash_depth(hash);  // return value not checked on purpose
     feed_last_hash_depth(hash);
 
     path_struct->array_depth_count -= 1;
@@ -307,7 +314,10 @@ static bool path_update(void) {
         }
         feed_last_hash_depth(hash);
 
-        ui_712_queue_struct_to_review();
+        // TODO: Find a better way to show inner structs in verbose mode when it might be
+        //       an empty array of structs in which case we don't want to show it but the
+        //       size is only known later
+        // ui_712_queue_struct_to_review();
         path_depth_list_push();
     }
     return true;
@@ -421,6 +431,8 @@ bool path_new_array_depth(const uint8_t *const data, uint8_t length) {
     uint8_t total_count = 0;
     uint8_t pidx;
     bool is_custom;
+    uint8_t array_size;
+    uint8_t array_depth_count_bak;
 
     if (path_struct == NULL) {
         apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED;
@@ -430,6 +442,8 @@ bool path_new_array_depth(const uint8_t *const data, uint8_t length) {
         return false;
     }
 
+    array_size = *data;
+    array_depth_count_bak = path_struct->array_depth_count;
     for (pidx = 0; pidx < path_struct->depth_count; ++pidx) {
         if ((field_ptr = get_nth_field(NULL, pidx + 1)) == NULL) {
             apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED;
@@ -442,7 +456,7 @@ bool path_new_array_depth(const uint8_t *const data, uint8_t length) {
             }
             total_count += depth_count;
             if (total_count > path_struct->array_depth_count) {
-                if (!check_and_add_array_depth(depth, total_count, pidx, *data)) {
+                if (!check_and_add_array_depth(depth, total_count, pidx, array_size)) {
                     return false;
                 }
                 break;
@@ -463,9 +477,18 @@ bool path_new_array_depth(const uint8_t *const data, uint8_t length) {
         cx_sha3_t *hash_ctx = get_last_hash_ctx();
         cx_sha3_t *old_ctx = hash_ctx - 1;
 
-        memcpy(hash_ctx, old_ctx, sizeof(*old_ctx));
+        if (array_size > 0) {
+            memcpy(hash_ctx, old_ctx, sizeof(*old_ctx));
+        } else {
+            cx_keccak_init(hash_ctx, 256);
+        }
         cx_keccak_init(old_ctx, 256);  // init hash
     }
+    if (array_size == 0) {
+        do {
+            path_advance();
+        } while (path_struct->array_depth_count != array_depth_count_bak);
+    }
 
     return true;
 }
@@ -515,7 +538,7 @@ static bool path_advance_in_array(void) {
 
         if ((path_struct->array_depth_count > 0) &&
             (arr_depth->path_index == (path_struct->depth_count - 1))) {
-            arr_depth->size -= 1;
+            if (arr_depth->size > 0) arr_depth->size -= 1;
             if (arr_depth->size == 0) {
                 array_depth_list_pop();
                 end_reached = true;
diff --git a/src_features/signMessageEIP712_common/common_712.c b/src_features/signMessageEIP712_common/common_712.c
index abc1fd509..084a528bb 100644
--- a/src_features/signMessageEIP712_common/common_712.c
+++ b/src_features/signMessageEIP712_common/common_712.c
@@ -7,7 +7,7 @@
 
 static const uint8_t EIP_712_MAGIC[] = {0x19, 0x01};
 
-unsigned int ui_712_approve_cb() {
+unsigned int ui_712_approve_cb(void) {
     uint8_t privateKeyData[INT256_LENGTH];
     uint8_t hash[INT256_LENGTH];
     uint8_t signature[100];
@@ -75,7 +75,7 @@ unsigned int ui_712_approve_cb() {
     return 0;  // do not redraw the widget
 }
 
-unsigned int ui_712_reject_cb() {
+unsigned int ui_712_reject_cb(void) {
     reset_app_context();
     G_io_apdu_buffer[0] = 0x69;
     G_io_apdu_buffer[1] = 0x85;
diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c
index 199ccbbe0..a107439f5 100644
--- a/src_features/signTx/logic_signTx.c
+++ b/src_features/signTx/logic_signTx.c
@@ -136,6 +136,7 @@ customStatus_e customProcessor(txContext_t *context) {
                 }
                 dataContext.tokenContext.fieldIndex++;
                 dataContext.tokenContext.fieldOffset = 0;
+                memset(dataContext.tokenContext.data, 0, sizeof(dataContext.tokenContext.data));
                 return CUSTOM_HANDLED;
             }
 
@@ -195,7 +196,8 @@ static void address_to_string(uint8_t *in,
 }
 
 static void raw_fee_to_string(uint256_t *rawFee, char *displayBuffer, uint32_t displayBufferSize) {
-    const char *feeTicker = get_network_ticker();
+    uint64_t chain_id = get_tx_chain_id();
+    const char *feeTicker = get_displayable_ticker(&chain_id);
     uint8_t tickerOffset = 0;
     uint32_t i;
 
@@ -262,10 +264,10 @@ static void nonce_to_string(const txInt256_t *nonce, char *out, size_t out_size)
 }
 
 static void get_network_as_string(char *out, size_t out_size) {
-    const char *name = get_network_name();
+    uint64_t chain_id = get_tx_chain_id();
+    const char *name = get_network_name_from_chain_id(&chain_id);
     if (name == NULL) {
         // No network name found so simply copy the chain ID as the network name.
-        uint64_t chain_id = get_chain_id();
         u64_to_string(chain_id, out, out_size);
     } else {
         // Network name found, simply copy it.
@@ -312,13 +314,14 @@ static int strcasecmp_workaround(const char *str1, const char *str2) {
 void finalizeParsing(bool direct) {
     char displayBuffer[50];
     uint8_t decimals = WEI_TO_ETHER;
-    const char *ticker = get_network_ticker();
+    uint64_t chain_id = get_tx_chain_id();
+    const char *ticker = get_displayable_ticker(&chain_id);
     ethPluginFinalize_t pluginFinalize;
     bool use_standard_UI = true;
 
     // Verify the chain
     if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) {
-        uint64_t id = get_chain_id();
+        uint64_t id = get_tx_chain_id();
 
         if (chainConfig->chainId != id) {
             PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId);
@@ -423,8 +426,8 @@ void finalizeParsing(bool direct) {
     }
 
     // User has just validated a swap but ETH received apdus about a non standard plugin / contract
-    if (called_from_swap && !use_standard_UI) {
-        PRINTF("ERR_SILENT_MODE_CHECK_FAILED, called_from_swap\n");
+    if (G_called_from_swap && !use_standard_UI) {
+        PRINTF("ERR_SILENT_MODE_CHECK_FAILED, G_called_from_swap\n");
         THROW(ERR_SILENT_MODE_CHECK_FAILED);
     }
 
@@ -446,7 +449,7 @@ void finalizeParsing(bool direct) {
                           sizeof(displayBuffer),
                           &global_sha3,
                           chainConfig->chainId);
-        if (called_from_swap) {
+        if (G_called_from_swap) {
             // Ensure the values are the same that the ones that have been previously validated
             if (strcasecmp_workaround(strings.common.fullAddress, displayBuffer) != 0) {
                 PRINTF("ERR_SILENT_MODE_CHECK_FAILED, address check failed\n");
@@ -465,7 +468,7 @@ void finalizeParsing(bool direct) {
                        ticker,
                        displayBuffer,
                        sizeof(displayBuffer));
-        if (called_from_swap) {
+        if (G_called_from_swap) {
             // Ensure the values are the same that the ones that have been previously validated
             if (strcmp(strings.common.fullAmount, displayBuffer) != 0) {
                 PRINTF("ERR_SILENT_MODE_CHECK_FAILED, amount check failed\n");
@@ -483,7 +486,7 @@ void finalizeParsing(bool direct) {
                                   &tmpContent.txContent.startgas,
                                   displayBuffer,
                                   sizeof(displayBuffer));
-    if (called_from_swap) {
+    if (G_called_from_swap) {
         // Ensure the values are the same that the ones that have been previously validated
         if (strcmp(strings.common.maxFee, displayBuffer) != 0) {
             PRINTF("ERR_SILENT_MODE_CHECK_FAILED, fees check failed\n");
@@ -509,7 +512,7 @@ void finalizeParsing(bool direct) {
 
     // If called from swap, the user as already validated a standard transaction
     // We have already checked the fields of this transaction above
-    no_consent_check = called_from_swap && use_standard_UI;
+    no_consent_check = G_called_from_swap && use_standard_UI;
 
 #ifdef NO_CONSENT
     no_consent_check = true;
diff --git a/src_features/signTx/ui_common_signTx.c b/src_features/signTx/ui_common_signTx.c
index ef8171f25..e57bb2125 100644
--- a/src_features/signTx/ui_common_signTx.c
+++ b/src_features/signTx/ui_common_signTx.c
@@ -2,12 +2,14 @@
 #include "shared_context.h"
 #include "utils.h"
 #include "common_ui.h"
+#include "handle_swap_sign_transaction.h"
 
 unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_element_t *e) {
     uint8_t privateKeyData[INT256_LENGTH];
     uint8_t signature[100];
     cx_ecfp_private_key_t privateKey;
     uint32_t tx = 0;
+    int err;
     io_seproxyhal_io_heartbeat();
     os_perso_derive_node_bip32(CX_CURVE_256K1,
                                tmpCtx.transactionContext.bip32.path,
@@ -59,10 +61,19 @@ unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_elemen
     tx = 65;
     G_io_apdu_buffer[tx++] = 0x90;
     G_io_apdu_buffer[tx++] = 0x00;
+
     // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
-    if (called_from_swap) {
-        os_sched_exit(0);
+    err = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
+    if (G_called_from_swap) {
+        PRINTF("G_called_from_swap\n");
+
+        // If we are in swap mode and have validated a TX, we send it and immediately quit
+        if (err == 0) {
+            finalize_exchange_sign_transaction(true);
+        } else {
+            PRINTF("Unrecoverable\n");
+            os_sched_exit(-1);
+        }
     }
     reset_app_context();
     // Display back the original UX
diff --git a/src_nbgl/ui_approve_tx.c b/src_nbgl/ui_approve_tx.c
new file mode 100644
index 000000000..a6253c35d
--- /dev/null
+++ b/src_nbgl/ui_approve_tx.c
@@ -0,0 +1,306 @@
+#include <ctype.h>
+#include <nbgl_page.h>
+#include "shared_context.h"
+#include "ui_callbacks.h"
+#include "ui_nbgl.h"
+#include "ethUtils.h"
+#include "ui_signing.h"
+#include "plugins.h"
+#include "domain_name.h"
+
+#define TEXT_TX "transaction"
+// 1 more than actually displayed on screen, because of calculations in StaticReview
+#define MAX_PLUGIN_ITEMS_PER_SCREEN 4
+#define TAG_MAX_LEN                 43
+#define VALUE_MAX_LEN               79
+enum {
+    REJECT_TOKEN,
+    START_REVIEW_TOKEN,
+};
+
+static nbgl_layoutTagValue_t pair;
+// these buffers are used as circular
+static char title_buffer[MAX_PLUGIN_ITEMS_PER_SCREEN][TAG_MAX_LEN];
+static char msg_buffer[MAX_PLUGIN_ITEMS_PER_SCREEN][VALUE_MAX_LEN];
+static nbgl_layoutTagValueList_t useCaseTagValueList;
+static nbgl_pageInfoLongPress_t infoLongPress;
+
+struct tx_approval_context_t {
+    bool fromPlugin;
+    bool blindSigning;
+    bool displayNetwork;
+#ifdef HAVE_DOMAIN_NAME
+    bool domain_name_match;
+#endif
+};
+
+static struct tx_approval_context_t tx_approval_context;
+
+static void reviewContinueCommon(void);
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_tx_cancel(NULL);
+    memset(&tx_approval_context, 0, sizeof(tx_approval_context));
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_tx_ok(NULL);
+    memset(&tx_approval_context, 0, sizeof(tx_approval_context));
+}
+
+static void onConfirmAbandon(void) {
+    nbgl_useCaseStatus("Transaction rejected", false, reviewReject);
+}
+
+static void rejectTransactionQuestion(void) {
+    nbgl_useCaseConfirm(REJECT_QUESTION(TEXT_TX),
+                        NULL,
+                        REJECT_CONFIRM_BUTTON,
+                        RESUME(TEXT_TX),
+                        onConfirmAbandon);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        nbgl_useCaseStatus("TRANSACTION\nSIGNED", true, confirmTransation);
+    } else {
+        rejectTransactionQuestion();
+    }
+}
+
+// called by NBGL to get the tag/value pair corresponding to pairIndex
+static nbgl_layoutTagValue_t *getTagValuePair(uint8_t pairIndex) {
+    static int counter = 0;
+
+    if (tx_approval_context.fromPlugin) {
+        if (pairIndex < dataContext.tokenContext.pluginUiMaxItems) {
+            // for the next dataContext.tokenContext.pluginUiMaxItems items, get tag/value from
+            // plugin_ui_get_item_internal()
+            dataContext.tokenContext.pluginUiCurrentItem = pairIndex;
+            plugin_ui_get_item_internal((uint8_t *) title_buffer[counter],
+                                        TAG_MAX_LEN,
+                                        (uint8_t *) msg_buffer[counter],
+                                        VALUE_MAX_LEN);
+            pair.item = title_buffer[counter];
+            pair.value = msg_buffer[counter];
+        } else {
+            pairIndex -= dataContext.tokenContext.pluginUiMaxItems;
+            // for the last 1 (or 2), tags are fixed
+            if (tx_approval_context.displayNetwork && (pairIndex == 0)) {
+                pair.item = "Network";
+                pair.value = strings.common.network_name;
+            } else {
+                pair.item = "Max fees";
+                pair.value = strings.common.maxFee;
+            }
+        }
+    } else {
+        uint8_t target_index = 0;
+
+        if (pairIndex == target_index++) {
+            pair.item = "Amount";
+            pair.value = strings.common.fullAmount;
+        }
+#ifdef HAVE_DOMAIN_NAME
+        if (tx_approval_context.domain_name_match) {
+            if (pairIndex == target_index++) {
+                pair.item = "Domain";
+                pair.value = g_domain_name;
+            }
+        }
+        if (!tx_approval_context.domain_name_match || N_storage.verbose_domain_name) {
+#endif  // HAVE_DOMAIN_NAME
+            if (pairIndex == target_index++) {
+                pair.item = "Address";
+                pair.value = strings.common.fullAddress;
+            }
+#ifdef HAVE_DOMAIN_NAME
+        }
+#endif  // HAVE_DOMAIN_NAME
+        if (N_storage.displayNonce) {
+            if (pairIndex == target_index++) {
+                pair.item = "Nonce";
+                pair.value = strings.common.nonce;
+            }
+        }
+        if (pairIndex == target_index++) {
+            pair.item = "Max fees";
+            pair.value = strings.common.maxFee;
+        }
+        if (pairIndex == target_index++) {
+            pair.item = "Network";
+            pair.value = strings.common.network_name;
+        }
+    }
+    // counter is used as index to circular buffer
+    counter++;
+    if (counter == MAX_PLUGIN_ITEMS_PER_SCREEN) {
+        counter = 0;
+    }
+    return &pair;
+}
+
+static void pageCallback(int token, uint8_t index) {
+    (void) index;
+    nbgl_pageRelease(pageContext);
+    if (token == REJECT_TOKEN) {
+        reviewReject();
+    } else if (token == START_REVIEW_TOKEN) {
+        reviewContinueCommon();
+    }
+}
+
+static void reviewContinue(void) {
+    if (tx_approval_context.blindSigning) {
+        nbgl_pageInfoDescription_t info = {
+            .centeredInfo.icon = &C_round_warning_64px,
+            .centeredInfo.text1 = "Blind Signing",
+            .centeredInfo.text2 =
+                "This transaction cannot be\nsecurely interpreted by Ledger\nStax. It might put "
+                "your assets\nat risk.",
+            .centeredInfo.text3 = NULL,
+            .centeredInfo.style = LARGE_CASE_INFO,
+            .centeredInfo.offsetY = -32,
+            .footerText = REJECT(TEXT_TX),
+            .footerToken = REJECT_TOKEN,
+            .tapActionText = "Tap to continue",
+            .tapActionToken = START_REVIEW_TOKEN,
+            .topRightStyle = NO_BUTTON_STYLE,
+            .actionButtonText = NULL,
+            .tuneId = TUNE_TAP_CASUAL};
+
+        if (pageContext != NULL) {
+            nbgl_pageRelease(pageContext);
+            pageContext = NULL;
+        }
+        pageContext = nbgl_pageDrawInfo(&pageCallback, NULL, &info);
+    } else {
+        reviewContinueCommon();
+    }
+}
+
+static const nbgl_icon_details_t *get_tx_icon(void) {
+    const nbgl_icon_details_t *icon = NULL;
+
+    if (tx_approval_context.fromPlugin && (pluginType == EXTERNAL)) {
+        if (caller_app && caller_app->name) {
+            if ((strlen(strings.common.fullAddress) == strlen(caller_app->name)) &&
+                (strcmp(strings.common.fullAddress, caller_app->name) == 0)) {
+                icon = get_app_icon(true);
+            }
+        }
+    } else {
+        icon = get_app_icon(false);
+    }
+    return icon;
+}
+
+static void reviewContinueCommon(void) {
+    uint8_t nbPairs = 0;
+
+    if (tx_approval_context.fromPlugin) {
+        // plugin id + max items + fees
+        nbPairs += dataContext.tokenContext.pluginUiMaxItems + 1;
+    } else {
+        nbPairs += 3;
+        if (N_storage.displayNonce) {
+            nbPairs++;
+        }
+#ifdef HAVE_DOMAIN_NAME
+        uint64_t chain_id = get_tx_chain_id();
+        tx_approval_context.domain_name_match =
+            has_domain_name(&chain_id, tmpContent.txContent.destination);
+        if (tx_approval_context.domain_name_match && N_storage.verbose_domain_name) {
+            nbPairs += 1;
+        }
+#endif  // HAVE_DOMAIN_NAME
+    }
+
+    if (tx_approval_context.displayNetwork) {
+        nbPairs++;
+    }
+
+    useCaseTagValueList.pairs = NULL;
+    useCaseTagValueList.callback = getTagValuePair;
+    useCaseTagValueList.startIndex = 0;
+    useCaseTagValueList.nbPairs = nbPairs;  ///< number of pairs in pairs array
+    useCaseTagValueList.smallCaseForValue = false;
+    useCaseTagValueList.wrapping = false;
+    infoLongPress.icon = get_tx_icon();
+    infoLongPress.text = tx_approval_context.fromPlugin ? g_stax_shared_buffer : SIGN(TEXT_TX);
+    infoLongPress.longPressText = SIGN_BUTTON;
+    nbgl_useCaseStaticReview(&useCaseTagValueList, &infoLongPress, REJECT(TEXT_TX), reviewChoice);
+}
+
+// Replace "Review" by "Sign" and add questionmark
+static void prepare_sign_text(void) {
+    uint8_t sign_length = strlen("Sign");
+    uint8_t review_length = strlen("Review");
+
+    memmove(g_stax_shared_buffer, "Sign", sign_length);
+    memmove(g_stax_shared_buffer + sign_length,
+            g_stax_shared_buffer + review_length,
+            strlen(g_stax_shared_buffer) - review_length + 1);
+    strlcat(g_stax_shared_buffer, "?", sizeof(g_stax_shared_buffer));
+}
+
+// Force operation to be lowercase
+static void get_lowercase_operation(char *dst, size_t dst_len) {
+    const char *src = strings.common.fullAmount;
+    size_t idx;
+
+    for (idx = 0; (idx < dst_len - 1) && (src[idx] != '\0'); ++idx) {
+        dst[idx] = (char) tolower((int) src[idx]);
+    }
+    dst[idx] = '\0';
+}
+
+static void buildFirstPage(void) {
+    if (tx_approval_context.fromPlugin) {
+        char op_name[sizeof(strings.common.fullAmount)];
+        plugin_ui_get_id();
+
+        get_lowercase_operation(op_name, sizeof(op_name));
+        if (pluginType == EXTERNAL) {
+            snprintf(g_stax_shared_buffer,
+                     sizeof(g_stax_shared_buffer),
+                     "Review transaction\nto %s\non %s",
+                     op_name,
+                     strings.common.fullAddress);
+        } else {
+            snprintf(g_stax_shared_buffer,
+                     sizeof(g_stax_shared_buffer),
+                     "Review transaction\nto %s\n%s",
+                     op_name,
+                     strings.common.fullAddress);
+        }
+        nbgl_useCaseReviewStart(get_tx_icon(),
+                                g_stax_shared_buffer,
+                                NULL,
+                                REJECT(TEXT_TX),
+                                reviewContinue,
+                                rejectTransactionQuestion);
+        prepare_sign_text();
+    } else {
+        nbgl_useCaseReviewStart(get_tx_icon(),
+                                REVIEW(TEXT_TX),
+                                NULL,
+                                REJECT(TEXT_TX),
+                                reviewContinue,
+                                rejectTransactionQuestion);
+    }
+}
+
+void ux_approve_tx(bool fromPlugin) {
+    tx_approval_context.blindSigning =
+        !fromPlugin && tmpContent.txContent.dataPresent && !N_storage.contractDetails;
+    tx_approval_context.fromPlugin = fromPlugin;
+    tx_approval_context.displayNetwork = false;
+
+    uint64_t chain_id = get_tx_chain_id();
+    if (chainConfig->chainId == ETHEREUM_MAINNET_CHAINID && chain_id != chainConfig->chainId) {
+        tx_approval_context.displayNetwork = true;
+    }
+
+    buildFirstPage();
+}
diff --git a/src_nbgl/ui_confirm_parameter_selector.c b/src_nbgl/ui_confirm_parameter_selector.c
new file mode 100644
index 000000000..80418e18c
--- /dev/null
+++ b/src_nbgl/ui_confirm_parameter_selector.c
@@ -0,0 +1,83 @@
+#include "common_ui.h"
+#include "ui_signing.h"
+#include "ui_nbgl.h"
+#include "network.h"
+
+typedef enum { PARAMETER_CONFIRMATION, SELECTOR_CONFIRMATION } e_confirmation_type;
+
+static nbgl_layoutTagValue_t pair;
+static e_confirmation_type confirm_type;
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_data_cancel(NULL);
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_data_ok(NULL);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        confirmTransation();
+    } else {
+        reviewReject();
+    }
+}
+
+static bool displayTransactionPage(uint8_t page, nbgl_pageContent_t *content) {
+    if (page == 0) {
+        pair.item = (confirm_type == PARAMETER_CONFIRMATION) ? "Parameter" : "Selector";
+        pair.value = strings.tmp.tmp;
+        content->type = TAG_VALUE_LIST;
+        content->tagValueList.nbPairs = 1;
+        content->tagValueList.pairs = (nbgl_layoutTagValue_t *) &pair;
+    } else if (page == 1) {
+        snprintf(g_stax_shared_buffer,
+                 sizeof(g_stax_shared_buffer),
+                 "Confirm %s",
+                 (confirm_type == PARAMETER_CONFIRMATION) ? "parameter" : "selector");
+        content->type = INFO_LONG_PRESS, content->infoLongPress.icon = get_app_icon(true);
+        content->infoLongPress.text = g_stax_shared_buffer;
+        content->infoLongPress.longPressText = "Hold to confirm";
+    } else {
+        return false;
+    }
+    // valid page so return true
+    return true;
+}
+
+static void reviewContinue(void) {
+    snprintf(g_stax_shared_buffer,
+             sizeof(g_stax_shared_buffer),
+             "Reject %s",
+             (confirm_type == PARAMETER_CONFIRMATION) ? "parameter" : "selector");
+    nbgl_useCaseRegularReview(0,
+                              2,
+                              g_stax_shared_buffer,
+                              NULL,
+                              displayTransactionPage,
+                              reviewChoice);
+}
+
+static void buildScreen(void) {
+    snprintf(g_stax_shared_buffer,
+             sizeof(g_stax_shared_buffer),
+             "Verify %s",
+             (confirm_type == PARAMETER_CONFIRMATION) ? "parameter" : "selector");
+    nbgl_useCaseReviewStart(get_app_icon(true),
+                            g_stax_shared_buffer,
+                            NULL,
+                            REJECT_BUTTON,
+                            reviewContinue,
+                            reviewReject);
+}
+
+void ui_confirm_parameter(void) {
+    confirm_type = PARAMETER_CONFIRMATION;
+    buildScreen();
+}
+
+void ui_confirm_selector(void) {
+    confirm_type = SELECTOR_CONFIRMATION;
+    buildScreen();
+}
diff --git a/src_nbgl/ui_display_privacy.c b/src_nbgl/ui_display_privacy.c
new file mode 100644
index 000000000..2b08175c9
--- /dev/null
+++ b/src_nbgl/ui_display_privacy.c
@@ -0,0 +1,69 @@
+#include "common_ui.h"
+#include "ui_signing.h"
+#include "ui_nbgl.h"
+#include "ui_callbacks.h"
+#include "nbgl_use_case.h"
+#include "network.h"
+
+static nbgl_layoutTagValue_t pairs[2];
+static char *review_string;
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_privacy_cancel(NULL);
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_privacy_ok(NULL);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        confirmTransation();
+    } else {
+        reviewReject();
+    }
+}
+
+static bool displayTransactionPage(uint8_t page, nbgl_pageContent_t *content) {
+    if (page == 0) {
+        pairs[0].item = "Address";
+        pairs[0].value = strings.common.fullAddress;
+        pairs[1].item = "Key";
+        pairs[1].value = strings.common.fullAmount;
+
+        content->type = TAG_VALUE_LIST;
+        content->tagValueList.nbPairs = 2;
+        content->tagValueList.pairs = (nbgl_layoutTagValue_t *) pairs;
+    } else if (page == 1) {
+        content->type = INFO_LONG_PRESS, content->infoLongPress.icon = get_app_icon(true);
+        content->infoLongPress.text = review_string;
+        content->infoLongPress.longPressText = "Hold to approve";
+    } else {
+        return false;
+    }
+    // valid page so return true
+    return true;
+}
+
+static void reviewContinue(void) {
+    nbgl_useCaseRegularReview(0, 2, REJECT_BUTTON, NULL, displayTransactionPage, reviewChoice);
+}
+
+static void buildFirstPage(void) {
+    nbgl_useCaseReviewStart(get_app_icon(true),
+                            review_string,
+                            NULL,
+                            REJECT_BUTTON,
+                            reviewContinue,
+                            reviewReject);
+}
+
+void ui_display_privacy_public_key(void) {
+    review_string = (char *) "Provide public\nprivacy key";
+    buildFirstPage();
+}
+
+void ui_display_privacy_shared_secret(void) {
+    review_string = (char *) "Provide public\nsecret key";
+    buildFirstPage();
+}
diff --git a/src_nbgl/ui_get_eth2_public_key.c b/src_nbgl/ui_get_eth2_public_key.c
new file mode 100644
index 000000000..9f388df27
--- /dev/null
+++ b/src_nbgl/ui_get_eth2_public_key.c
@@ -0,0 +1,30 @@
+#include <nbgl_page.h>
+#include "shared_context.h"
+#include "ui_callbacks.h"
+#include "ui_nbgl.h"
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_address_cancel(NULL);
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_address_ok(NULL);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        // display a status page and go back to main
+        nbgl_useCaseStatus("ADDRESS\nVERIFIED", true, confirmTransation);
+    } else {
+        nbgl_useCaseStatus("Address verification\ncancelled", false, reviewReject);
+    }
+}
+
+static void buildScreen(void) {
+    snprintf(strings.tmp.tmp, 100, "0x%.*H", 48, tmpCtx.publicKeyContext.publicKey.W);
+    nbgl_useCaseAddressConfirmation(strings.tmp.tmp, reviewChoice);
+}
+
+void ui_display_public_eth2(void) {
+    buildScreen();
+}
\ No newline at end of file
diff --git a/src_nbgl/ui_get_public_key.c b/src_nbgl/ui_get_public_key.c
new file mode 100644
index 000000000..5966737ea
--- /dev/null
+++ b/src_nbgl/ui_get_public_key.c
@@ -0,0 +1,28 @@
+#include <nbgl_page.h>
+#include "shared_context.h"
+#include "ui_callbacks.h"
+#include "ui_nbgl.h"
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_address_cancel(NULL);
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_address_ok(NULL);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        // display a status page and go back to main
+        nbgl_useCaseStatus("ADDRESS\nVERIFIED", true, confirmTransation);
+    } else {
+        nbgl_useCaseStatus("Address verification\ncancelled", false, reviewReject);
+    }
+}
+
+static void buildScreen(void) {
+    nbgl_useCaseAddressConfirmation(strings.common.fullAddress, reviewChoice);
+}
+void ui_display_public_key(void) {
+    buildScreen();
+}
\ No newline at end of file
diff --git a/src_nbgl/ui_get_stark_public_key.c b/src_nbgl/ui_get_stark_public_key.c
new file mode 100644
index 000000000..ce5778750
--- /dev/null
+++ b/src_nbgl/ui_get_stark_public_key.c
@@ -0,0 +1,29 @@
+#include <nbgl_page.h>
+#include "shared_context.h"
+#include "ui_callbacks.h"
+#include "ui_nbgl.h"
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_address_cancel(NULL);
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_stark_pubkey_ok(NULL);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        // display a status page and go back to main
+        nbgl_useCaseStatus("ADDRESS\nVERIFIED", true, confirmTransation);
+    } else {
+        nbgl_useCaseStatus("Address verification\ncancelled", false, reviewReject);
+    }
+}
+
+static void buildScreen(void) {
+    nbgl_useCaseAddressConfirmation(strings.tmp.tmp, reviewChoice);
+}
+
+void ui_display_stark_public(void) {
+    buildScreen();
+}
\ No newline at end of file
diff --git a/src_nbgl/ui_idle.c b/src_nbgl/ui_idle.c
new file mode 100644
index 000000000..faa47ca99
--- /dev/null
+++ b/src_nbgl/ui_idle.c
@@ -0,0 +1,63 @@
+#include "common_ui.h"
+#include "shared_context.h"
+#include "ui_nbgl.h"
+#include "nbgl_use_case.h"
+#include "glyphs.h"
+#include "network.h"
+
+char g_stax_shared_buffer[SHARED_BUFFER_SIZE] = {0};
+nbgl_page_t *pageContext;
+
+#define FORMAT_PLUGIN "This app enables clear\nsigning transactions for\nthe %s dApp."
+
+void releaseContext(void) {
+    if (pageContext != NULL) {
+        nbgl_pageRelease(pageContext);
+        pageContext = NULL;
+    }
+}
+
+void app_quit(void) {
+    // exit app here
+    os_sched_exit(-1);
+}
+
+const nbgl_icon_details_t *get_app_icon(bool caller_icon) {
+    const nbgl_icon_details_t *icon = NULL;
+
+    if (caller_icon && caller_app) {
+        if (caller_app->icon) {
+            icon = caller_app->icon;
+        }
+    } else {
+        icon = &ICONGLYPH;
+    }
+    if (icon == NULL) {
+        PRINTF("%s(%s) returned NULL!\n", __func__, (caller_icon ? "true" : "false"));
+    }
+    return icon;
+}
+
+void ui_idle(void) {
+    const char *app_name = NULL;
+    const char *tagline = NULL;
+
+    if (caller_app) {
+        app_name = caller_app->name;
+
+        if (caller_app->type == CALLER_TYPE_PLUGIN) {
+            snprintf(g_stax_shared_buffer, sizeof(g_stax_shared_buffer), FORMAT_PLUGIN, app_name);
+            tagline = g_stax_shared_buffer;
+        }
+    } else {  // Ethereum app
+        uint64_t mainnet_chain_id = ETHEREUM_MAINNET_CHAINID;
+        app_name = get_network_name_from_chain_id(&mainnet_chain_id);
+    }
+
+    nbgl_useCaseHome((char *) app_name,
+                     get_app_icon(true),
+                     tagline,
+                     true,
+                     ui_menu_settings,
+                     app_quit);
+}
diff --git a/src_nbgl/ui_message_signing.c b/src_nbgl/ui_message_signing.c
new file mode 100644
index 000000000..51e1a7ec2
--- /dev/null
+++ b/src_nbgl/ui_message_signing.c
@@ -0,0 +1,50 @@
+#include "ui_nbgl.h"
+#include "ui_signing.h"
+#include "ui_logic.h"
+#include "ui_message_signing.h"
+#include "glyphs.h"
+
+static void (*g_approved_func)(void) = NULL;
+static void (*g_rejected_func)(void) = NULL;
+
+static void ui_message_rejection_handler() {
+    nbgl_useCaseStatus("Message signing\ncancelled", false, g_rejected_func);
+}
+
+static void ui_message_confirm_rejection(void) {
+    nbgl_useCaseConfirm(REJECT_QUESTION(TEXT_MESSAGE),
+                        NULL,
+                        REJECT_CONFIRM_BUTTON,
+                        RESUME(TEXT_MESSAGE),
+                        ui_message_rejection_handler);
+}
+
+void ui_message_review_choice(bool confirm) {
+    if (confirm) {
+        nbgl_useCaseStatus("MESSAGE\nSIGNED", true, g_approved_func);
+    } else {
+        ui_message_confirm_rejection();
+    }
+}
+
+void ui_message_start(const char *title,
+                      void (*start_func)(void),
+                      void (*approved_func)(void),
+                      void (*rejected_func)(void)) {
+    g_approved_func = approved_func;
+    g_rejected_func = rejected_func;
+    nbgl_useCaseReviewStart(&C_Message_64px,
+                            title,
+                            NULL,
+                            REJECT_BUTTON,
+                            start_func,
+                            ui_message_confirm_rejection);
+}
+
+void ui_message_712_approved(void) {
+    ui_712_approve();
+}
+
+void ui_message_712_rejected(void) {
+    ui_712_reject();
+}
diff --git a/src_nbgl/ui_message_signing.h b/src_nbgl/ui_message_signing.h
new file mode 100644
index 000000000..008f57400
--- /dev/null
+++ b/src_nbgl/ui_message_signing.h
@@ -0,0 +1,20 @@
+#ifndef UI_MESSAGE_SIGNING_H_
+#define UI_MESSAGE_SIGNING_H_
+
+#include <stdbool.h>
+
+#define TEXT_MESSAGE       "message"
+#define TEXT_TYPED_MESSAGE "typed " TEXT_MESSAGE
+#define TEXT_REVIEW_EIP712 REVIEW(TEXT_TYPED_MESSAGE)
+#define TEXT_SIGN_EIP712   SIGN(TEXT_TYPED_MESSAGE)
+
+void ui_message_review_choice(bool confirm);
+void ui_message_start(const char *title,
+                      void (*start_func)(void),
+                      void (*approved_func)(void),
+                      void (*rejected_func)(void));
+
+void ui_message_712_approved(void);
+void ui_message_712_rejected(void);
+
+#endif  // UI_MESSAGE_SIGNING_H_
diff --git a/src_nbgl/ui_nbgl.h b/src_nbgl/ui_nbgl.h
new file mode 100644
index 000000000..921d604d9
--- /dev/null
+++ b/src_nbgl/ui_nbgl.h
@@ -0,0 +1,21 @@
+#ifndef _UI_NBGL_H_
+#define _UI_NBGL_H_
+
+#include <nbgl_use_case.h>
+#include <nbgl_page.h>
+#include <shared_context.h>
+
+#define SHARED_BUFFER_SIZE SHARED_CTX_FIELD_1_SIZE
+extern char g_stax_shared_buffer[SHARED_BUFFER_SIZE];
+
+extern nbgl_page_t* pageContext;
+
+void releaseContext(void);
+
+const nbgl_icon_details_t* get_app_icon(bool caller_icon);
+
+void ui_idle(void);
+void ui_menu_settings(void);
+void ui_menu_about(void);
+
+#endif  // _UI_NBGL_H_
diff --git a/src_nbgl/ui_settings.c b/src_nbgl/ui_settings.c
new file mode 100644
index 000000000..9d3656cc9
--- /dev/null
+++ b/src_nbgl/ui_settings.c
@@ -0,0 +1,132 @@
+#include "common_ui.h"
+#include "ui_nbgl.h"
+#include "nbgl_use_case.h"
+
+static const char* const infoTypes[] = {"Version", APPNAME " App"};
+static const char* const infoContents[] = {APPVERSION, "(c) " BUILD_YEAR " Ledger"};
+
+enum {
+    BLIND_SIGNING_TOKEN = FIRST_USER_TOKEN,
+    DEBUG_TOKEN,
+    NONCE_TOKEN,
+#ifdef HAVE_EIP712_FULL_SUPPORT
+    EIP712_VERBOSE_TOKEN,
+#endif  // HAVE_EIP712_FULL_SUPPORT
+#ifdef HAVE_DOMAIN_NAME
+    DOMAIN_NAME_VERBOSE_TOKEN
+#endif  // HAVE_DOMAIN_NAME
+};
+
+static nbgl_layoutSwitch_t switches[3];
+
+static bool navCallback(uint8_t page, nbgl_pageContent_t* content) {
+    uint8_t index = 0;
+
+    switch (page) {
+        case 0:
+            content->type = INFOS_LIST;
+            content->infosList.nbInfos = 2;
+            content->infosList.infoTypes = (const char**) infoTypes;
+            content->infosList.infoContents = (const char**) infoContents;
+            break;
+
+        case 1:
+            switches[index++] =
+                (nbgl_layoutSwitch_t){.initState = N_storage.dataAllowed ? ON_STATE : OFF_STATE,
+                                      .text = "Blind signing",
+                                      .subText = "Enable transaction blind\nsigning",
+                                      .token = BLIND_SIGNING_TOKEN,
+                                      .tuneId = TUNE_TAP_CASUAL};
+            switches[index++] =
+                (nbgl_layoutSwitch_t){.initState = N_storage.contractDetails ? ON_STATE : OFF_STATE,
+                                      .text = "Debug",
+                                      .subText = "Display contract data\ndetails",
+                                      .token = DEBUG_TOKEN,
+                                      .tuneId = TUNE_TAP_CASUAL};
+            switches[index++] =
+                (nbgl_layoutSwitch_t){.initState = N_storage.displayNonce ? ON_STATE : OFF_STATE,
+                                      .text = "Nonce",
+                                      .subText = "Display account nonce\nin transaction",
+                                      .token = NONCE_TOKEN,
+                                      .tuneId = TUNE_TAP_CASUAL};
+
+            content->type = SWITCHES_LIST;
+            content->switchesList.nbSwitches = index;
+            content->switchesList.switches = (nbgl_layoutSwitch_t*) switches;
+            break;
+
+        case 2:
+#ifdef HAVE_EIP712_FULL_SUPPORT
+            switches[index++] =
+                (nbgl_layoutSwitch_t){.initState = N_storage.verbose_eip712 ? ON_STATE : OFF_STATE,
+                                      .text = "Verbose EIP712",
+                                      .subText = "Ignore filtering and\ndisplay raw content",
+                                      .token = EIP712_VERBOSE_TOKEN,
+                                      .tuneId = TUNE_TAP_CASUAL};
+#endif  // HAVE_EIP712_FULL_SUPPORT
+#ifdef HAVE_DOMAIN_NAME
+            switches[index++] = (nbgl_layoutSwitch_t){
+                .initState = N_storage.verbose_domain_name ? ON_STATE : OFF_STATE,
+                .text = "Verbose domains",
+                .subText = "Show resolved address",
+                .token = DOMAIN_NAME_VERBOSE_TOKEN,
+                .tuneId = TUNE_TAP_CASUAL};
+#endif  // HAVE_DOMAIN_NAME
+
+            content->type = SWITCHES_LIST;
+            content->switchesList.nbSwitches = index;
+            content->switchesList.switches = (nbgl_layoutSwitch_t*) switches;
+            break;
+
+        default:
+            return false;
+            break;
+    }
+
+    return true;
+}
+
+static void controlsCallback(int token, uint8_t index) {
+    (void) index;
+    uint8_t value;
+    switch (token) {
+        case BLIND_SIGNING_TOKEN:
+            value = (N_storage.dataAllowed ? 0 : 1);
+            nvm_write((void*) &N_storage.dataAllowed, (void*) &value, sizeof(uint8_t));
+            break;
+        case DEBUG_TOKEN:
+            value = (N_storage.contractDetails ? 0 : 1);
+            nvm_write((void*) &N_storage.contractDetails, (void*) &value, sizeof(uint8_t));
+            break;
+        case NONCE_TOKEN:
+            value = (N_storage.displayNonce ? 0 : 1);
+            nvm_write((void*) &N_storage.displayNonce, (void*) &value, sizeof(uint8_t));
+            break;
+#ifdef HAVE_EIP712_FULL_SUPPORT
+        case EIP712_VERBOSE_TOKEN:
+            value = (N_storage.verbose_eip712 ? 0 : 1);
+            nvm_write((void*) &N_storage.verbose_eip712, (void*) &value, sizeof(uint8_t));
+            break;
+#endif  // HAVE_EIP712_FULL_SUPPORT
+#ifdef HAVE_DOMAIN_NAME
+        case DOMAIN_NAME_VERBOSE_TOKEN:
+            value = (N_storage.verbose_domain_name ? 0 : 1);
+            nvm_write((void*) &N_storage.verbose_domain_name, (void*) &value, sizeof(uint8_t));
+            break;
+#endif  // HAVE_DOMAIN_NAME
+    }
+}
+
+void ui_menu_settings(void) {
+    uint8_t nb_screens = 2;
+#if defined(HAVE_EIP712_FULL_SUPPORT) || defined(HAVE_DOMAIN_NAME)
+    nb_screens += 1;
+#endif
+    nbgl_useCaseSettings(APPNAME " settings",
+                         0,
+                         nb_screens,
+                         false,
+                         ui_idle,
+                         navCallback,
+                         controlsCallback);
+}
diff --git a/src_nbgl/ui_sign_712.c b/src_nbgl/ui_sign_712.c
new file mode 100644
index 000000000..4d9aae7a3
--- /dev/null
+++ b/src_nbgl/ui_sign_712.c
@@ -0,0 +1,87 @@
+#ifdef HAVE_EIP712_FULL_SUPPORT
+
+#include "common_ui.h"
+#include "ui_nbgl.h"
+#include "ui_logic.h"
+#include "common_712.h"
+#include "nbgl_use_case.h"
+#include "network.h"
+#include "ui_message_signing.h"
+#include "ui_signing.h"
+
+static nbgl_layoutTagValue_t pair;
+
+static bool display_sign_page(uint8_t page, nbgl_pageContent_t *content) {
+    (void) page;
+    content->type = INFO_LONG_PRESS, content->infoLongPress.icon = get_app_icon(true);
+    content->infoLongPress.text = TEXT_SIGN_EIP712;
+    content->infoLongPress.longPressText = SIGN_BUTTON;
+    return true;
+}
+
+static bool display_review_page(uint8_t page, nbgl_pageContent_t *content) {
+    bool ret;
+    uint16_t len;
+
+    switch (page) {
+        case 0:
+            // limit the value to one page
+            nbgl_getTextMaxLenInNbLines(BAGL_FONT_INTER_MEDIUM_32px,
+                                        strings.tmp.tmp,
+                                        SCREEN_WIDTH - (2 * BORDER_MARGIN),
+                                        NB_MAX_LINES_IN_REVIEW,
+                                        &len);
+            strings.tmp.tmp[len] = '\0';
+
+            pair.item = strings.tmp.tmp2;
+            pair.value = strings.tmp.tmp;
+            content->type = TAG_VALUE_LIST;
+            content->tagValueList.nbPairs = 1;
+            content->tagValueList.pairs = &pair;
+            content->tagValueList.wrapping = false;
+            ret = true;
+            break;
+
+        case 1:
+            switch (ui_712_next_field()) {
+                case EIP712_NO_MORE_FIELD:
+                    ui_712_switch_to_sign();
+                    ret = true;
+                    break;
+                case EIP712_FIELD_INCOMING:
+                case EIP712_FIELD_LATER:
+                default:
+                    break;
+            }
+            __attribute__((fallthrough));
+
+        default:
+            ret = false;
+            break;
+    }
+    return ret;
+}
+
+static void handle_display(nbgl_navCallback_t cb) {
+    nbgl_useCaseRegularReview(0, 0, REJECT_BUTTON, NULL, cb, ui_message_review_choice);
+}
+
+void ui_712_start(void) {
+    g_position = UI_SIGNING_POSITION_START;
+    ui_message_start(TEXT_REVIEW_EIP712,
+                     &ui_712_switch_to_message,
+                     &ui_message_712_approved,
+                     &ui_message_712_rejected);
+}
+
+void ui_712_switch_to_message(void) {
+    g_position = UI_SIGNING_POSITION_REVIEW;
+    handle_display(display_review_page);
+}
+
+void ui_712_switch_to_sign(void) {
+    g_position = UI_SIGNING_POSITION_SIGN;
+    handle_display(display_sign_page);
+}
+
+#endif  // HAVE_EIP712_FULL_SUPPORT
diff --git a/src_nbgl/ui_sign_712_v0.c b/src_nbgl/ui_sign_712_v0.c
new file mode 100644
index 000000000..ec38eeaf7
--- /dev/null
+++ b/src_nbgl/ui_sign_712_v0.c
@@ -0,0 +1,78 @@
+#include "common_ui.h"
+#include "ui_nbgl.h"
+#include "common_712.h"
+#include "network.h"
+#include "ethUtils.h"
+#include "ui_message_signing.h"
+#include "ui_signing.h"
+
+static nbgl_layoutTagValue_t pairs[2];
+
+static void start_review(void);  // forward declaration
+
+static char *format_hash(const uint8_t *hash, char *buffer, size_t buffer_size, size_t offset) {
+    snprintf(buffer + offset, buffer_size - offset, "0x%.*H", KECCAK256_HASH_BYTESIZE, hash);
+    return buffer + offset;
+}
+
+static bool display_review_page(uint8_t page, nbgl_pageContent_t *content) {
+    if (page == 0) {
+        pairs[0].item = "Domain hash";
+        pairs[0].value = format_hash(tmpCtx.messageSigningContext712.domainHash,
+                                     strings.tmp.tmp,
+                                     sizeof(strings.tmp.tmp),
+                                     0);
+        pairs[1].item = "Message hash";
+        pairs[1].value = format_hash(tmpCtx.messageSigningContext712.messageHash,
+                                     strings.tmp.tmp,
+                                     sizeof(strings.tmp.tmp),
+                                     70);
+
+        content->type = TAG_VALUE_LIST;
+        content->tagValueList.nbPairs = 2;
+        content->tagValueList.pairs = (nbgl_layoutTagValue_t *) pairs;
+    } else if (page == 1) {
+        g_position = UI_SIGNING_POSITION_SIGN;
+        content->type = INFO_LONG_PRESS, content->infoLongPress.icon = get_app_icon(true);
+        content->infoLongPress.text = TEXT_SIGN_EIP712;
+        content->infoLongPress.longPressText = SIGN_BUTTON;
+    } else {
+        return false;
+    }
+    // valid page so return true
+    return true;
+}
+
+static void display_review(void) {
+    uint8_t page;
+
+    switch (g_position) {
+        case UI_SIGNING_POSITION_REVIEW:
+            page = 0;
+            break;
+        case UI_SIGNING_POSITION_SIGN:
+            page = 1;
+            break;
+        default:
+            return;  // should not happen
+    }
+    nbgl_useCaseRegularReview(page,
+                              2,
+                              REJECT_BUTTON,
+                              NULL,
+                              display_review_page,
+                              ui_message_review_choice);
+}
+
+static void start_review(void) {
+    g_position = UI_SIGNING_POSITION_REVIEW;
+    display_review();
+}
+
+void ui_sign_712_v0(void) {
+    g_position = UI_SIGNING_POSITION_START;
+    ui_message_start(TEXT_REVIEW_EIP712,
+                     &start_review,
+                     &ui_message_712_approved,
+                     &ui_message_712_rejected);
+}
diff --git a/src_nbgl/ui_sign_message.c b/src_nbgl/ui_sign_message.c
new file mode 100644
index 000000000..6d85f80e8
--- /dev/null
+++ b/src_nbgl/ui_sign_message.c
@@ -0,0 +1,154 @@
+#include <nbgl_page.h>
+#include "shared_context.h"
+#include "ui_callbacks.h"
+#include "ui_nbgl.h"
+#include "sign_message.h"
+#include "glyphs.h"
+#include "nbgl_use_case.h"
+#include "common_ui.h"
+#include "ui_message_signing.h"
+#include "ui_signing.h"
+
+#define TEXT_REVIEW_EIP191 REVIEW(TEXT_MESSAGE)
+#define TEXT_SIGN_EIP191   SIGN(TEXT_MESSAGE)
+
+typedef enum {
+    UI_191_ACTION_IDLE = 0,
+    UI_191_ACTION_ADVANCE_IN_MESSAGE,
+    UI_191_ACTION_GO_TO_SIGN
+} e_ui_191_action;
+
+static e_ui_191_action g_action;
+
+static bool skip_message;
+
+static nbgl_layoutTagValue_t pair;
+
+static uint32_t eip191MessageIdx = 0;
+static uint32_t stringsTmpTmpIdx = 0;
+
+static void reject_message(void) {
+    io_seproxyhal_touch_signMessage_cancel();
+}
+
+static void sign_message(void) {
+    io_seproxyhal_touch_signMessage_ok();
+}
+
+static bool display_message(nbgl_pageContent_t *content) {
+    uint16_t len = 0;
+    bool reached;
+
+    if (g_action == UI_191_ACTION_ADVANCE_IN_MESSAGE) {
+        strncpy(g_stax_shared_buffer + eip191MessageIdx,
+                strings.tmp.tmp + stringsTmpTmpIdx,
+                SHARED_BUFFER_SIZE - eip191MessageIdx);
+        reached = nbgl_getTextMaxLenInNbLines(BAGL_FONT_INTER_MEDIUM_32px,
+                                              (char *) g_stax_shared_buffer,
+                                              SCREEN_WIDTH - (2 * BORDER_MARGIN),
+                                              NB_MAX_LINES_IN_REVIEW,
+                                              &len);
+
+        stringsTmpTmpIdx = len - eip191MessageIdx;
+        eip191MessageIdx = len;
+        g_stax_shared_buffer[eip191MessageIdx] = '\0';
+
+        if (!reached && eip191MessageIdx < SHARED_BUFFER_SIZE) {
+            stringsTmpTmpIdx = 0;
+            question_switcher();
+
+            if (g_action != UI_191_ACTION_GO_TO_SIGN) {
+                return false;
+            }
+        } else if (reached || eip191MessageIdx == SHARED_BUFFER_SIZE) {
+            eip191MessageIdx = 0;
+        }
+    }
+
+    pair.value = g_stax_shared_buffer;
+    pair.item = "Message";
+    content->type = TAG_VALUE_LIST;
+    content->tagValueList.nbPairs = 1;
+    content->tagValueList.pairs = &pair;
+    content->tagValueList.smallCaseForValue = false;
+    content->tagValueList.nbMaxLinesForValue = NB_MAX_LINES_IN_REVIEW;
+    content->tagValueList.wrapping = false;
+
+    if ((g_action != UI_191_ACTION_IDLE) && (stringsTmpTmpIdx >= strlen(strings.tmp.tmp))) {
+        // Fetch the next content to display into strings.tmp.tmp buffer.
+        stringsTmpTmpIdx = 0;
+        question_switcher();
+    }
+    return true;
+}
+
+static bool display_sign(nbgl_pageContent_t *content) {
+    bool ret = false;
+
+    if (g_position != UI_SIGNING_POSITION_SIGN) {
+        content->type = INFO_LONG_PRESS, content->infoLongPress.icon = &C_Message_64px;
+        content->infoLongPress.text = TEXT_SIGN_EIP191;
+        content->infoLongPress.longPressText = SIGN_BUTTON;
+        g_position = UI_SIGNING_POSITION_SIGN;
+        ret = true;
+    }
+    return ret;
+}
+
+static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) {
+    bool ret = true;
+
+    if (page == LAST_PAGE_FOR_REVIEW) {  // was skipped
+        skip_message = true;
+        skip_rest_of_message();
+    }
+    if ((g_action != UI_191_ACTION_GO_TO_SIGN) && (g_position != UI_SIGNING_POSITION_SIGN)) {
+        if (skip_message) {
+            // do not refresh when this callback triggers after user validation
+            ret = false;
+        } else {
+            ret = display_message(content);
+        }
+    } else {
+        // the last page must contain a long press button
+        ret = display_sign(content);
+    }
+    return ret;
+}
+
+static void continue_review(void) {
+    nbgl_useCaseForwardOnlyReview(REJECT_BUTTON, NULL, nav_callback, ui_message_review_choice);
+}
+
+void ui_191_start(void) {
+    g_position = UI_SIGNING_POSITION_START;
+
+    skip_message = false;
+    eip191MessageIdx = 0;
+    stringsTmpTmpIdx = 0;
+
+    ui_message_start(TEXT_REVIEW_EIP191, &ui_191_switch_to_message, &sign_message, &reject_message);
+}
+
+void ui_191_switch_to_message(void) {
+    g_position = UI_SIGNING_POSITION_REVIEW;
+    g_action = UI_191_ACTION_ADVANCE_IN_MESSAGE;
+    // No question mechanism on Stax:
+    // Message is already displayed
+    continue_review();
+}
+
+void ui_191_switch_to_sign(void) {
+    g_action = UI_191_ACTION_GO_TO_SIGN;
+    // Next nav_callback callback must display
+    // the hold to approve screen
+    if (skip_message) {
+        continue_review();  // to force screen refresh
+    }
+}
+
+void ui_191_switch_to_question(void) {
+    // No question mechanism on Stax:
+    // Always display the next message chunk.
+    continue_displaying_message();
+}
diff --git a/src_nbgl/ui_signing.c b/src_nbgl/ui_signing.c
new file mode 100644
index 000000000..2becdf07d
--- /dev/null
+++ b/src_nbgl/ui_signing.c
@@ -0,0 +1,3 @@
+#include "ui_signing.h"
+
+e_ui_signing_position g_position;
diff --git a/src_nbgl/ui_signing.h b/src_nbgl/ui_signing.h
new file mode 100644
index 000000000..e7b8f71a2
--- /dev/null
+++ b/src_nbgl/ui_signing.h
@@ -0,0 +1,21 @@
+#ifndef UI_SIGNING_H_
+#define UI_SIGNING_H_
+
+#define SIGN_BUTTON           "Hold to sign"
+#define REJECT_BUTTON         "Reject"
+#define SIGN(msg)             "Sign " msg "?"
+#define REVIEW(msg)           "Review " msg
+#define REJECT(msg)           "Reject " msg
+#define REJECT_QUESTION(msg)  REJECT(msg) "?"
+#define REJECT_CONFIRM_BUTTON "Yes, reject"
+#define RESUME(msg)           "Go back to " msg
+
+typedef enum {
+    UI_SIGNING_POSITION_START = 0,
+    UI_SIGNING_POSITION_REVIEW,
+    UI_SIGNING_POSITION_SIGN
+} e_ui_signing_position;
+
+extern e_ui_signing_position g_position;
+
+#endif  // UI_SIGNING_H_
diff --git a/src_nbgl/ui_stark_limit_order.c b/src_nbgl/ui_stark_limit_order.c
new file mode 100644
index 000000000..89cfdbf83
--- /dev/null
+++ b/src_nbgl/ui_stark_limit_order.c
@@ -0,0 +1,68 @@
+#include "common_ui.h"
+#include "ui_signing.h"
+#include "ui_nbgl.h"
+#include "ui_callbacks.h"
+#include "nbgl_use_case.h"
+#include "network.h"
+
+#ifdef HAVE_STARKWARE
+
+static nbgl_layoutTagValue_t pairs[3];
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_tx_cancel(NULL);
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_stark_ok(NULL);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        confirmTransation();
+    } else {
+        reviewReject();
+    }
+}
+
+static bool displayTransactionPage(uint8_t page, nbgl_pageContent_t *content) {
+    if (page == 0) {
+        pairs[0].item = "Sell";
+        pairs[0].value = strings.common.fullAmount;
+        pairs[1].item = "Buy";
+        pairs[1].value = strings.common.maxFee;
+        pairs[2].item = "Token Account";
+        pairs[2].value = strings.common.fullAddress;
+
+        content->type = TAG_VALUE_LIST;
+        content->tagValueList.nbPairs = 3;
+        content->tagValueList.pairs = (nbgl_layoutTagValue_t *) pairs;
+    } else if (page == 1) {
+        content->type = INFO_LONG_PRESS, content->infoLongPress.icon = get_app_icon(false);
+        content->infoLongPress.text = "Review stark limit order";
+        content->infoLongPress.longPressText = SIGN_BUTTON;
+    } else {
+        return false;
+    }
+    // valid page so return true
+    return true;
+}
+
+static void reviewContinue(void) {
+    nbgl_useCaseRegularReview(0, 2, REJECT_BUTTON, NULL, displayTransactionPage, reviewChoice);
+}
+
+static void buildFirstPage(void) {
+    nbgl_useCaseReviewStart(get_app_icon(false),
+                            "Review stark limit order",
+                            NULL,
+                            REJECT_BUTTON,
+                            reviewContinue,
+                            reviewReject);
+}
+
+void ui_stark_limit_order(void) {
+    buildFirstPage();
+}
+
+#endif
diff --git a/src_nbgl/ui_stark_transfer.c b/src_nbgl/ui_stark_transfer.c
new file mode 100644
index 000000000..d7decfbca
--- /dev/null
+++ b/src_nbgl/ui_stark_transfer.c
@@ -0,0 +1,133 @@
+#include <nbgl_page.h>
+#include "shared_context.h"
+#include "ui_callbacks.h"
+#include "ui_nbgl.h"
+#include "ui_signing.h"
+#include "starkDisplayUtils.h"
+#include "ethUtils.h"
+#include "network.h"
+
+#ifdef HAVE_STARKWARE
+
+static nbgl_layoutTagValue_t pairs[3];
+static char condAddressBuffer[43];
+struct stark_transfer_context {
+    bool selfTransfer;
+    bool conditional;
+};
+
+static struct stark_transfer_context context;
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_tx_cancel(NULL);
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_stark_ok(NULL);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        confirmTransation();
+    } else {
+        reviewReject();
+    }
+}
+
+static bool displayTransactionPage(uint8_t page, nbgl_pageContent_t *content) {
+    uint8_t count = 0;
+    if (page == 0) {
+        pairs[count].item = "Amount";
+        pairs[count].value = tmpContent.tmp;
+        count++;
+
+        if (context.selfTransfer == false && context.conditional == false) {
+            pairs[count].item = "Master Account";
+            pairs[count].value = strings.tmp.tmp;
+            count++;
+        }
+        if (context.conditional) {
+            stark_sign_display_master_account();
+            pairs[count].item = "Master Account";
+            pairs[count].value = strings.tmp.tmp;
+            count++;
+        }
+
+        pairs[count].item = "Token Account";
+        pairs[count].value = strings.tmp.tmp2;
+        count++;
+
+        content->type = TAG_VALUE_LIST;
+        content->tagValueList.nbPairs = count;
+        content->tagValueList.pairs = (nbgl_layoutTagValue_t *) pairs;
+
+        return true;
+    }
+    if (page == 1) {
+        if (context.conditional) {
+            getEthDisplayableAddress(dataContext.starkContext.conditionAddress,
+                                     condAddressBuffer,
+                                     sizeof(condAddressBuffer),
+                                     &global_sha3,
+                                     chainConfig->chainId);
+            pairs[0].item = "Cond. Address";
+            pairs[0].value = condAddressBuffer;
+
+            stark_sign_display_condition_fact();
+            pairs[1].item = "Cond. Address";
+            pairs[1].value = strings.tmp.tmp;
+
+            content->type = TAG_VALUE_LIST;
+            content->tagValueList.nbPairs = 2;
+            content->tagValueList.pairs = (nbgl_layoutTagValue_t *) pairs;
+
+            return true;
+        } else {
+            page++;
+        }
+    }
+    if (page == 2) {
+        content->type = INFO_LONG_PRESS, content->infoLongPress.icon = get_app_icon(false);
+        content->infoLongPress.text = "Review transaction";
+        content->infoLongPress.longPressText = SIGN_BUTTON;
+        return true;
+    }
+
+    return false;
+}
+
+static void reviewContinue(void) {
+    nbgl_useCaseRegularReview(0,
+                              context.conditional ? 3 : 2,
+                              REJECT_BUTTON,
+                              NULL,
+                              displayTransactionPage,
+                              reviewChoice);
+}
+
+void ui_stark_transfer(bool selfTransfer, bool conditional) {
+    context.selfTransfer = selfTransfer;
+    context.conditional = conditional;
+    char *subTitle;
+    if (conditional) {
+        if (selfTransfer) {
+            subTitle = (char *) "Conditional Self Transfer";
+        } else {
+            subTitle = (char *) "Conditional Transfer";
+        }
+    } else {
+        if (selfTransfer) {
+            subTitle = (char *) "Self Transfer";
+        } else {
+            subTitle = (char *) "Transfer";
+        }
+    }
+    nbgl_useCaseReviewStart(get_app_icon(false),
+                            "Review stark\ntransaction",
+                            subTitle,
+                            REJECT_BUTTON,
+                            reviewContinue,
+                            reviewReject);
+}
+
+#endif  // #ifdef HAVE_STARKWARE
diff --git a/src_nbgl/ui_stark_unsafe_sign.c b/src_nbgl/ui_stark_unsafe_sign.c
new file mode 100644
index 000000000..45a8556db
--- /dev/null
+++ b/src_nbgl/ui_stark_unsafe_sign.c
@@ -0,0 +1,70 @@
+#include "common_ui.h"
+#include "ui_signing.h"
+#include "ui_nbgl.h"
+#include "ui_callbacks.h"
+#include "nbgl_use_case.h"
+#include "network.h"
+
+#ifdef HAVE_STARKWARE
+
+static nbgl_layoutTagValue_t pairs[2];
+static char from_account[64];
+static char message_hash[64];
+
+static void reviewReject(void) {
+    io_seproxyhal_touch_tx_cancel(NULL);
+}
+
+static void confirmTransation(void) {
+    io_seproxyhal_touch_stark_unsafe_sign_ok(NULL);
+}
+
+static void reviewChoice(bool confirm) {
+    if (confirm) {
+        confirmTransation();
+    } else {
+        reviewReject();
+    }
+}
+
+static bool displayTransactionPage(uint8_t page, nbgl_pageContent_t *content) {
+    snprintf(from_account, sizeof(from_account), "0x%.*H", 32, dataContext.starkContext.w1);
+    snprintf(message_hash, sizeof(message_hash), "0x%.*H", 32, dataContext.starkContext.w2);
+
+    if (page == 0) {
+        pairs[0].item = "From Account";
+        pairs[0].value = from_account;
+        pairs[1].item = "Hash";
+        pairs[1].value = message_hash;
+        content->type = TAG_VALUE_LIST;
+        content->tagValueList.nbPairs = 2;
+        content->tagValueList.pairs = (nbgl_layoutTagValue_t *) pairs;
+    } else if (page == 1) {
+        content->type = INFO_LONG_PRESS, content->infoLongPress.icon = get_app_icon(false);
+        content->infoLongPress.text = "Unsafe Stark Sign";
+        content->infoLongPress.longPressText = SIGN_BUTTON;
+    } else {
+        return false;
+    }
+    // valid page so return true
+    return true;
+}
+
+static void reviewContinue(void) {
+    nbgl_useCaseRegularReview(0, 2, REJECT_BUTTON, NULL, displayTransactionPage, reviewChoice);
+}
+
+static void buildFirstPage(void) {
+    nbgl_useCaseReviewStart(get_app_icon(false),
+                            "Unsafe Stark Sign",
+                            NULL,
+                            REJECT_BUTTON,
+                            reviewContinue,
+                            reviewReject);
+}
+
+void ui_stark_unsafe_sign(void) {
+    buildFirstPage();
+}
+
+#endif  // HAVE_STARKWARE
diff --git a/src_nbgl/ui_warning_contract_data.c b/src_nbgl/ui_warning_contract_data.c
new file mode 100644
index 000000000..2619dce4e
--- /dev/null
+++ b/src_nbgl/ui_warning_contract_data.c
@@ -0,0 +1,21 @@
+#include <nbgl_page.h>
+#include "shared_context.h"
+#include "ui_callbacks.h"
+#include "ui_nbgl.h"
+
+static void ui_warning_contract_data_choice(bool confirm) {
+    if (confirm) {
+        ui_idle();
+    } else {
+        ui_menu_settings();
+    }
+}
+
+void ui_warning_contract_data(void) {
+    nbgl_useCaseChoice(&C_warning64px,
+                       "This message cannot\nbe clear-signed",
+                       "Enable blind-signing in\nthe settings to sign\nthis transaction.",
+                       "Exit",
+                       "Go to settings",
+                       ui_warning_contract_data_choice);
+}
diff --git a/src_plugins/erc20/erc20_plugin.c b/src_plugins/erc20/erc20_plugin.c
index 04062d82e..220e05f9d 100644
--- a/src_plugins/erc20/erc20_plugin.c
+++ b/src_plugins/erc20/erc20_plugin.c
@@ -182,7 +182,11 @@ void erc20_plugin_call(int message, void *parameters) {
 
         case ETH_PLUGIN_QUERY_CONTRACT_ID: {
             ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
+#ifdef HAVE_NBGL
+            strlcpy(msg->name, "ERC20 token", msg->nameLength);
+#else
             strlcpy(msg->name, "Type", msg->nameLength);
+#endif
             strlcpy(msg->version, "Approve", msg->versionLength);
             msg->result = ETH_PLUGIN_RESULT_OK;
         } break;
diff --git a/src_plugins/eth2/eth2_plugin.c b/src_plugins/eth2/eth2_plugin.c
index 29ea29947..c93c82ec6 100644
--- a/src_plugins/eth2/eth2_plugin.c
+++ b/src_plugins/eth2/eth2_plugin.c
@@ -212,7 +212,7 @@ void eth2_plugin_call(int message, void *parameters) {
                     strlcpy(msg->title, "Validator", msg->titleLength);
                     strlcpy(msg->msg, context->deposit_address, msg->msgLength);
                     msg->result = ETH_PLUGIN_RESULT_OK;
-                }
+                } break;
                 default:
                     break;
             }
diff --git a/tools/build_sdk.py b/tools/build_sdk.py
index a808e4aed..552bb25cf 100755
--- a/tools/build_sdk.py
+++ b/tools/build_sdk.py
@@ -82,10 +82,13 @@ def extract_from_c_files(sources, nodes_to_extract):
 
 def merge_headers(sources, nodes_to_extract):
     includes = [
+        '#include <stdbool.h>',
+        '#include <string.h>',
         '#include "os.h"',
         '#include "cx.h"',
-        '#include <stdbool.h>',
-        '#include <string.h>'
+        '#ifdef HAVE_NBGL',
+        '#include "nbgl_types.h"',
+        '#endif'
     ]
 
     body = extract_from_headers(sources, nodes_to_extract)
@@ -156,11 +159,12 @@ def merge_c_files(sources, nodes_to_extract):
         "src/shared_context.h",
         "src/eth_plugin_internal.h",
         "src/nft.h",
+        "src/swap_lib_calls.h"
     ]
     nodes_to_extract = {
         "#define": ["MAX_TICKER_LEN", "ADDRESS_LENGTH", "INT256_LENGTH", "WEI_TO_ETHER", "SELECTOR_SIZE", "PARAMETER_LENGTH", "RUN_APPLICATION", "COLLECTION_NAME_MAX_LEN"],
         "typedef enum": [],
-        "typedef struct": ["tokenDefinition_t", "txInt256_t", "txContent_t", "nftInfo_t"],
+        "typedef struct": ["tokenDefinition_t", "txInt256_t", "txContent_t", "nftInfo_t", "caller_app_t"],
         "typedef union": ["extraInfo_t"],
         "__attribute__((no_instrument_function)) inline": ["int allzeroes"],
         "const": ["HEXDIGITS"],


Test patch:
diff --git a/glyphs/blue_badge_rsk_testnet.gif b/glyphs/blue_badge_rsk_testnet.gif
deleted file mode 100644
index 5174214f3..000000000
Binary files a/glyphs/blue_badge_rsk_testnet.gif and /dev/null differ
diff --git a/glyphs/nanos_badge_rsk_testnet.gif b/glyphs/nanos_badge_rsk_testnet.gif
deleted file mode 100644
index 776f6454b..000000000
Binary files a/glyphs/nanos_badge_rsk_testnet.gif and /dev/null differ
diff --git a/glyphs/stax_rsk_testnet_64px.gif b/glyphs/stax_rsk_testnet_64px.gif
new file mode 100644
index 000000000..5e25ff6b2
Binary files /dev/null and b/glyphs/stax_rsk_testnet_64px.gif differ
diff --git a/glyphs/stax_tecratestnet_64px.gif b/glyphs/stax_tecratestnet_64px.gif
new file mode 100644
index 000000000..4fa9b491c
Binary files /dev/null and b/glyphs/stax_tecratestnet_64px.gif differ
diff --git a/icons/blue_app_rsk_testnet.gif b/icons/blue_app_rsk_testnet.gif
deleted file mode 100644
index 2fd05e6b7..000000000
Binary files a/icons/blue_app_rsk_testnet.gif and /dev/null differ
diff --git a/icons/nanos_app_tecratestnet.gif b/icons/nanos_app_tecratestnet.gif
old mode 100755
new mode 100644
diff --git a/icons/nanox_app_tecratestnet.gif b/icons/nanox_app_tecratestnet.gif
old mode 100755
new mode 100644
diff --git a/icons/rsk_testnet.png b/icons/rsk_testnet.png
deleted file mode 100644
index c69449b2b..000000000
Binary files a/icons/rsk_testnet.png and /dev/null differ
diff --git a/icons/stax_app_rsk_testnet.gif b/icons/stax_app_rsk_testnet.gif
new file mode 100644
index 000000000..a576134bc
Binary files /dev/null and b/icons/stax_app_rsk_testnet.gif differ
diff --git a/icons/stax_app_tecratestnet.gif b/icons/stax_app_tecratestnet.gif
new file mode 100644
index 000000000..a1ccb2d47
Binary files /dev/null and b/icons/stax_app_tecratestnet.gif differ
diff --git a/tests/ragger/app/client.py b/tests/ragger/app/client.py
index 9732c81a6..616670c0a 100644
--- a/tests/ragger/app/client.py
+++ b/tests/ragger/app/client.py
@@ -2,14 +2,9 @@
 from typing import Optional
 from ragger.backend import BackendInterface
 from ragger.utils import RAPDU
-from ragger.navigator import NavInsID, NavIns, NanoNavigator
-from .command_builder import EthereumCmdBuilder
-from .setting import SettingType, SettingImpl
+from .command_builder import CommandBuilder
 from .eip712 import EIP712FieldType
-from .response_parser import EthereumRespParser
 from .tlv import format_tlv
-import signal
-import time
 from pathlib import Path
 import keychain
 import rlp
@@ -41,58 +36,19 @@ class DOMAIN_NAME_TAG(IntEnum):
     ADDRESS = 0x22
 
 
-class EthereumClient:
-    _settings: dict[SettingType, SettingImpl] = {
-        SettingType.BLIND_SIGNING: SettingImpl(
-            [ "nanos", "nanox", "nanosp" ]
-        ),
-        SettingType.DEBUG_DATA: SettingImpl(
-            [ "nanos", "nanox", "nanosp" ]
-        ),
-        SettingType.NONCE: SettingImpl(
-            [ "nanos", "nanox", "nanosp" ]
-        ),
-        SettingType.VERBOSE_EIP712: SettingImpl(
-            [ "nanox", "nanosp" ]
-        ),
-        SettingType.VERBOSE_ENS: SettingImpl(
-            [ "nanox", "nanosp" ]
-        )
-    }
-    _click_delay = 1/4
-    _eip712_filtering = False
-
-    def __init__(self, client: BackendInterface, golden_run: bool):
+class EthAppClient:
+    def __init__(self, client: BackendInterface):
         self._client = client
-        self._chain_id = 1
-        self._cmd_builder = EthereumCmdBuilder()
-        self._resp_parser = EthereumRespParser()
-        self._nav = NanoNavigator(client, client.firmware, golden_run)
-        signal.signal(signal.SIGALRM, self._click_signal_timeout)
-        for setting in self._settings.values():
-            setting.value = False
+        self._cmd_builder = CommandBuilder()
 
     def _send(self, payload: bytearray):
         return self._client.exchange_async_raw(payload)
 
-    def _recv(self) -> RAPDU:
+    def response(self) -> RAPDU:
         return self._client._last_async_response
 
-    def _click_signal_timeout(self, _signum: int, _frame):
-        self._client.right_click()
-
-    def _enable_click_until_response(self):
-        signal.setitimer(signal.ITIMER_REAL,
-                         self._click_delay,
-                         self._click_delay)
-
-    def _disable_click_until_response(self):
-        signal.setitimer(signal.ITIMER_REAL, 0, 0)
-
     def eip712_send_struct_def_struct_name(self, name: str):
-        with self._send(self._cmd_builder.eip712_send_struct_def_struct_name(name)):
-            pass
-        return self._recv().status == 0x9000
+        return self._send(self._cmd_builder.eip712_send_struct_def_struct_name(name))
 
     def eip712_send_struct_def_struct_field(self,
                                             field_type: EIP712FieldType,
@@ -100,98 +56,45 @@ def eip712_send_struct_def_struct_field(self,
                                             type_size: int,
                                             array_levels: [],
                                             key_name: str):
-        with self._send(self._cmd_builder.eip712_send_struct_def_struct_field(
-                        field_type,
-                        type_name,
-                        type_size,
-                        array_levels,
-                        key_name)):
-            pass
-        return self._recv()
+        return self._send(self._cmd_builder.eip712_send_struct_def_struct_field(
+                          field_type,
+                          type_name,
+                          type_size,
+                          array_levels,
+                          key_name))
 
     def eip712_send_struct_impl_root_struct(self, name: str):
-        with self._send(self._cmd_builder.eip712_send_struct_impl_root_struct(name)):
-            self._enable_click_until_response()
-        self._disable_click_until_response()
-        return self._recv()
+        return self._send(self._cmd_builder.eip712_send_struct_impl_root_struct(name))
 
     def eip712_send_struct_impl_array(self, size: int):
-        with self._send(self._cmd_builder.eip712_send_struct_impl_array(size)):
-            pass
-        return self._recv()
+        return self._send(self._cmd_builder.eip712_send_struct_impl_array(size))
 
     def eip712_send_struct_impl_struct_field(self, raw_value: bytes):
-        for apdu in self._cmd_builder.eip712_send_struct_impl_struct_field(raw_value):
-            with self._send(apdu):
-                self._enable_click_until_response()
-            self._disable_click_until_response()
-            assert self._recv().status == 0x9000
-
-    def eip712_sign_new(self, bip32_path: str):
-        with self._send(self._cmd_builder.eip712_sign_new(bip32_path)):
-            time.sleep(0.5) # tight on timing, needed by the CI otherwise might fail sometimes
-            if not self._settings[SettingType.VERBOSE_EIP712].value and \
-               not self._eip712_filtering: # need to skip the message hash
-                self._client.right_click()
-                self._client.right_click()
-            self._client.both_click() # approve signature
-        resp = self._recv()
-        assert resp.status == 0x9000
-        return self._resp_parser.sign(resp.data)
+        chunks = self._cmd_builder.eip712_send_struct_impl_struct_field(raw_value)
+        for chunk in chunks[:-1]:
+            with self._send(chunk):
+                pass
+        return self._send(chunks[-1])
+
+    def eip712_sign_new(self, bip32_path: str, verbose: bool):
+        return self._send(self._cmd_builder.eip712_sign_new(bip32_path))
 
     def eip712_sign_legacy(self,
                            bip32_path: str,
                            domain_hash: bytes,
                            message_hash: bytes):
-        with self._send(self._cmd_builder.eip712_sign_legacy(bip32_path,
-                                                             domain_hash,
-                                                             message_hash)):
-            self._client.right_click() # sign typed message screen
-            for _ in range(2): # two hashes (domain + message)
-                if self._client.firmware.device == "nanos":
-                    screens_per_hash = 4
-                else:
-                    screens_per_hash = 2
-                for _ in range(screens_per_hash):
-                    self._client.right_click()
-            self._client.both_click() # approve signature
-
-        resp = self._recv()
-
-        assert resp.status == 0x9000
-        return self._resp_parser.sign(resp.data)
-
-    def settings_set(self, new_values: dict[SettingType, bool]):
-        # Go to settings
-        for _ in range(2):
-            self._client.right_click()
-        self._client.both_click()
-
-        for enum in self._settings.keys():
-            if self._client.firmware.device in self._settings[enum].devices:
-                if enum in new_values.keys():
-                    if new_values[enum] != self._settings[enum].value:
-                        self._client.both_click()
-                        self._settings[enum].value = new_values[enum]
-                self._client.right_click()
-        self._client.both_click()
+        return self._send(self._cmd_builder.eip712_sign_legacy(bip32_path,
+                                                               domain_hash,
+                                                               message_hash))
 
     def eip712_filtering_activate(self):
-        with self._send(self._cmd_builder.eip712_filtering_activate()):
-            pass
-        self._eip712_filtering = True
-        assert self._recv().status == 0x9000
+        return self._send(self._cmd_builder.eip712_filtering_activate())
 
     def eip712_filtering_message_info(self, name: str, filters_count: int, sig: bytes):
-        with self._send(self._cmd_builder.eip712_filtering_message_info(name, filters_count, sig)):
-            self._enable_click_until_response()
-        self._disable_click_until_response()
-        assert self._recv().status == 0x9000
+        return self._send(self._cmd_builder.eip712_filtering_message_info(name, filters_count, sig))
 
     def eip712_filtering_show_field(self, name: str, sig: bytes):
-        with self._send(self._cmd_builder.eip712_filtering_show_field(name, sig)):
-            pass
-        assert self._recv().status == 0x9000
+        return self._send(self._cmd_builder.eip712_filtering_show_field(name, sig))
 
     def send_fund(self,
                   bip32_path: str,
@@ -200,8 +103,7 @@ def send_fund(self,
                   gas_limit: int,
                   to: bytes,
                   amount: float,
-                  chain_id: int,
-                  screenshot_collection: str = None):
+                  chain_id: int):
         data = list()
         data.append(nonce)
         data.append(gas_price)
@@ -213,27 +115,14 @@ def send_fund(self,
         data.append(bytes())
         data.append(bytes())
 
-        for chunk in self._cmd_builder.sign(bip32_path, rlp.encode(data)):
+        chunks = self._cmd_builder.sign(bip32_path, rlp.encode(data))
+        for chunk in chunks[:-1]:
             with self._send(chunk):
-                nav_ins = NavIns(NavInsID.RIGHT_CLICK)
-                final_ins = [ NavIns(NavInsID.BOTH_CLICK) ]
-                target_text = "and send"
-                if screenshot_collection:
-                    self._nav.navigate_until_text_and_compare(nav_ins,
-                                                              final_ins,
-                                                              target_text,
-                                                              ROOT_SCREENSHOT_PATH,
-                                                              screenshot_collection)
-                else:
-                    self._nav.navigate_until_text(nav_ins,
-                                                  final_ins,
-                                                  target_text)
-
-    def get_challenge(self) -> int:
-        with self._send(self._cmd_builder.get_challenge()):
-            pass
-        resp = self._recv()
-        return self._resp_parser.challenge(resp.data)
+                pass
+        return self._send(chunks[-1])
+
+    def get_challenge(self):
+        return self._send(self._cmd_builder.get_challenge())
 
     def provide_domain_name(self, challenge: int, name: str, addr: bytes):
         payload  = format_tlv(DOMAIN_NAME_TAG.STRUCTURE_TYPE, 3) # TrustedDomainName
@@ -247,6 +136,8 @@ def provide_domain_name(self, challenge: int, name: str, addr: bytes):
         payload += format_tlv(DOMAIN_NAME_TAG.SIGNATURE,
                               keychain.sign_data(keychain.Key.DOMAIN_NAME, payload))
 
-        for chunk in self._cmd_builder.provide_domain_name(payload):
+        chunks = self._cmd_builder.provide_domain_name(payload)
+        for chunk in chunks[:-1]:
             with self._send(chunk):
                 pass
+        return self._send(chunks[-1])
diff --git a/tests/ragger/app/command_builder.py b/tests/ragger/app/command_builder.py
index aac10d014..ae3f730f8 100644
--- a/tests/ragger/app/command_builder.py
+++ b/tests/ragger/app/command_builder.py
@@ -29,7 +29,7 @@ class P2Type(IntEnum):
     FILTERING_CONTRACT_NAME = 0x0f
     FILTERING_FIELD_NAME = 0xff
 
-class EthereumCmdBuilder:
+class CommandBuilder:
     _CLA: int = 0xE0
 
     def _serialize(self,
@@ -103,6 +103,7 @@ def eip712_send_struct_impl_array(self, size: int) -> bytes:
                                data)
 
     def eip712_send_struct_impl_struct_field(self, data: bytearray) -> Iterator[bytes]:
+        chunks = list()
         # Add a 16-bit integer with the data's byte length (network byte order)
         data_w_length = bytearray()
         data_w_length.append((len(data) & 0xff00) >> 8)
@@ -110,11 +111,12 @@ def eip712_send_struct_impl_struct_field(self, data: bytearray) -> Iterator[byte
         data_w_length += data
         while len(data_w_length) > 0:
             p1 = P1Type.PARTIAL_SEND if len(data_w_length) > 0xff else P1Type.COMPLETE_SEND
-            yield self._serialize(InsType.EIP712_SEND_STRUCT_IMPL,
-                                  p1,
-                                  P2Type.STRUCT_FIELD,
-                                  data_w_length[:0xff])
+            chunks.append(self._serialize(InsType.EIP712_SEND_STRUCT_IMPL,
+                                          p1,
+                                          P2Type.STRUCT_FIELD,
+                                          data_w_length[:0xff]))
             data_w_length = data_w_length[0xff:]
+        return chunks
 
     def eip712_sign_new(self, bip32_path: str) -> bytes:
         data = pack_derivation_path(bip32_path)
@@ -167,29 +169,33 @@ def eip712_filtering_show_field(self, name: str, sig: bytes) -> bytes:
                                P2Type.FILTERING_FIELD_NAME,
                                self._eip712_filtering_send_name(name, sig))
 
-    def sign(self, bip32_path: str, rlp_data: bytes) -> Iterator[bytes]:
+    def sign(self, bip32_path: str, rlp_data: bytes) -> list[bytes]:
+        apdus = list()
         payload = pack_derivation_path(bip32_path)
         payload += rlp_data
         p1 = P1Type.SIGN_FIRST_CHUNK
         while len(payload) > 0:
-            yield self._serialize(InsType.SIGN,
-                                  p1,
-                                  0x00,
-                                  payload[:0xff])
+            apdus.append(self._serialize(InsType.SIGN,
+                                         p1,
+                                         0x00,
+                                         payload[:0xff]))
             payload = payload[0xff:]
             p1 = P1Type.SIGN_SUBSQT_CHUNK
+        return apdus
 
     def get_challenge(self) -> bytes:
         return self._serialize(InsType.GET_CHALLENGE, 0x00, 0x00)
 
-    def provide_domain_name(self, tlv_payload: bytes) -> bytes:
+    def provide_domain_name(self, tlv_payload: bytes) -> list[bytes]:
+        chunks = list()
         payload  = struct.pack(">H", len(tlv_payload))
         payload += tlv_payload
         p1 = 1
         while len(payload) > 0:
-            yield self._serialize(InsType.PROVIDE_DOMAIN_NAME,
-                                  p1,
-                                  0x00,
-                                  payload[:0xff])
+            chunks.append(self._serialize(InsType.PROVIDE_DOMAIN_NAME,
+                                          p1,
+                                          0x00,
+                                          payload[:0xff]))
             payload = payload[0xff:]
             p1 = 0
+        return chunks
diff --git a/tests/ragger/app/response_parser.py b/tests/ragger/app/response_parser.py
index 242f4cff5..5e73df498 100644
--- a/tests/ragger/app/response_parser.py
+++ b/tests/ragger/app/response_parser.py
@@ -1,18 +1,14 @@
-class EthereumRespParser:
-    def sign(self, data: bytes):
-        assert len(data) == (1 + 32 + 32)
+def signature(data: bytes) -> tuple[bytes, bytes, bytes]:
+    assert len(data) == (1 + 32 + 32)
 
-        v = data[0:1]
-        data = data[1:]
+    v = data[0:1]
+    data = data[1:]
+    r = data[0:32]
+    data = data[32:]
+    s = data[0:32]
 
-        r = data[0:32]
-        data = data[32:]
+    return v, r, s
 
-        s = data[0:32]
-        data = data[32:]
-
-        return v, r, s
-
-    def challenge(self, data: bytes) -> int:
-        assert len(data) == 4
-        return int.from_bytes(data, "big")
+def challenge(data: bytes) -> int:
+    assert len(data) == 4
+    return int.from_bytes(data, "big")
diff --git a/tests/ragger/app/setting.py b/tests/ragger/app/setting.py
deleted file mode 100644
index 7e79da72d..000000000
--- a/tests/ragger/app/setting.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from enum import IntEnum, auto
-from typing import List
-
-class SettingType(IntEnum):
-    BLIND_SIGNING = 0,
-    DEBUG_DATA = auto()
-    NONCE = auto()
-    VERBOSE_EIP712 = auto()
-    VERBOSE_ENS = auto()
-
-class SettingImpl:
-    devices: List[str]
-    value: bool
-
-    def __init__(self, devs: List[str]):
-        self.devices = devs
diff --git a/tests/ragger/app/settings.py b/tests/ragger/app/settings.py
new file mode 100644
index 000000000..ec6bf78b4
--- /dev/null
+++ b/tests/ragger/app/settings.py
@@ -0,0 +1,63 @@
+from enum import Enum, auto
+from typing import List
+from ragger.firmware import Firmware
+from ragger.navigator import Navigator, NavInsID, NavIns
+
+class SettingID(Enum):
+    BLIND_SIGNING = auto()
+    DEBUG_DATA = auto()
+    NONCE = auto()
+    VERBOSE_EIP712 = auto()
+    VERBOSE_ENS = auto()
+
+def get_device_settings(device: str) -> list[SettingID]:
+    if device == "nanos":
+        return [
+            SettingID.BLIND_SIGNING,
+            SettingID.DEBUG_DATA,
+            SettingID.NONCE
+        ]
+    if (device == "nanox") or (device == "nanosp") or (device == "stax"):
+        return [
+            SettingID.BLIND_SIGNING,
+            SettingID.DEBUG_DATA,
+            SettingID.NONCE,
+            SettingID.VERBOSE_EIP712,
+            SettingID.VERBOSE_ENS
+        ]
+    return []
+
+settings_per_page = 3
+
+def get_setting_position(device: str, setting: NavInsID) -> tuple[int, int]:
+    screen_height = 672 # px
+    header_height = 85 # px
+    footer_height = 124 # px
+    usable_height = screen_height - (header_height + footer_height)
+    setting_height = usable_height // settings_per_page
+    index_in_page = get_device_settings(device).index(setting) % settings_per_page
+    return 350, header_height + (setting_height * index_in_page) + (setting_height // 2)
+
+def settings_toggle(fw: Firmware, nav: Navigator, to_toggle: list[SettingID]):
+    moves = list()
+    settings = get_device_settings(fw.device)
+    # Assume the app is on the home page
+    if fw.device.startswith("nano"):
+        moves += [NavInsID.RIGHT_CLICK] * 2
+        moves += [NavInsID.BOTH_CLICK]
+        for setting in settings:
+            if setting in to_toggle:
+                moves += [NavInsID.BOTH_CLICK]
+            moves += [NavInsID.RIGHT_CLICK]
+        moves += [NavInsID.BOTH_CLICK] # Back
+    else:
+        moves += [NavInsID.USE_CASE_HOME_SETTINGS]
+        moves += [NavInsID.USE_CASE_SETTINGS_NEXT]
+        for setting in settings:
+            setting_idx = settings.index(setting)
+            if (setting_idx > 0) and (setting_idx % settings_per_page) == 0:
+                moves += [NavInsID.USE_CASE_SETTINGS_NEXT]
+            if setting in to_toggle:
+                moves += [NavIns(NavInsID.TOUCH, get_setting_position(fw.device, setting))]
+        moves += [NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT]
+    nav.navigate(moves, screen_change_before_first_instruction=False)
diff --git a/tests/ragger/conftest.py b/tests/ragger/conftest.py
index 68799b278..6dd6f4ba3 100644
--- a/tests/ragger/conftest.py
+++ b/tests/ragger/conftest.py
@@ -1,12 +1,4 @@
-import pytest
 from ragger.conftest import configuration
-from ragger.backend import BackendInterface
-from app.client import EthereumClient
-
-# This final fixture will return the properly configured app client, to be used in tests
-@pytest.fixture
-def app_client(backend: BackendInterface, golden_run: bool) -> EthereumClient:
-    return EthereumClient(backend, golden_run)
 
 # Pull all features from the base ragger conftest using the overridden configuration
 pytest_plugins = ("ragger.conftest.base_conftest", )
diff --git a/tests/ragger/eip712/InputData.py b/tests/ragger/eip712/InputData.py
index 02a96ebd0..6dd647131 100644
--- a/tests/ragger/eip712/InputData.py
+++ b/tests/ragger/eip712/InputData.py
@@ -4,15 +4,19 @@
 import sys
 import re
 import hashlib
-from app.client import EthereumClient, EIP712FieldType
+from app.client import EthAppClient, EIP712FieldType
 import keychain
+from typing import Callable
+import signal
 
 # global variables
-app_client: EthereumClient = None
+app_client: EthAppClient = None
 filtering_paths = None
 current_path = list()
 sig_ctx = {}
 
+autonext_handler: Callable = None
+
 
 
 
@@ -97,11 +101,12 @@ def send_struct_def_field(typename, keyname):
         type_enum = EIP712FieldType.CUSTOM
         typesize = None
 
-    app_client.eip712_send_struct_def_struct_field(type_enum,
-                                                   typename,
-                                                   typesize,
-                                                   array_lvls,
-                                                   keyname)
+    with app_client.eip712_send_struct_def_struct_field(type_enum,
+                                                        typename,
+                                                        typesize,
+                                                        array_lvls,
+                                                        keyname):
+        pass
     return (typename, type_enum, typesize, array_lvls)
 
 
@@ -191,7 +196,9 @@ def send_struct_impl_field(value, field):
         if path in filtering_paths.keys():
             send_filtering_show_field(filtering_paths[path])
 
-    app_client.eip712_send_struct_impl_struct_field(data)
+    with app_client.eip712_send_struct_impl_struct_field(data):
+        enable_autonext()
+    disable_autonext()
 
 
 
@@ -201,7 +208,8 @@ def evaluate_field(structs, data, field, lvls_left, new_level = True):
     if new_level:
         current_path.append(field["name"])
     if len(array_lvls) > 0 and lvls_left > 0:
-        app_client.eip712_send_struct_impl_array(len(data))
+        with app_client.eip712_send_struct_impl_array(len(data)):
+            pass
         idx = 0
         for subdata in data:
             current_path.append("[]")
@@ -252,7 +260,9 @@ def send_filtering_message_info(display_name: str, filters_count: int):
         to_sign.append(ord(char))
 
     sig = keychain.sign_data(keychain.Key.CAL, to_sign)
-    app_client.eip712_filtering_message_info(display_name, filters_count, sig)
+    with app_client.eip712_filtering_message_info(display_name, filters_count, sig):
+        enable_autonext()
+    disable_autonext()
 
 # ledgerjs doesn't actually sign anything, and instead uses already pre-computed signatures
 def send_filtering_show_field(display_name):
@@ -270,7 +280,8 @@ def send_filtering_show_field(display_name):
     for char in display_name:
         to_sign.append(ord(char))
     sig = keychain.sign_data(keychain.Key.CAL, to_sign)
-    app_client.eip712_filtering_show_field(display_name, sig)
+    with app_client.eip712_filtering_show_field(display_name, sig):
+        pass
 
 def read_filtering_file(domain, message, filtering_file_path):
     data_json = None
@@ -309,9 +320,29 @@ def init_signature_context(types, domain):
     schema_hash = hashlib.sha224(schema_str.encode())
     sig_ctx["schema_hash"] = bytearray.fromhex(schema_hash.hexdigest())
 
-def process_file(aclient: EthereumClient, input_file_path: str, filtering_file_path = None) -> bool:
+
+def next_timeout(_signum: int, _frame):
+    autonext_handler()
+
+def enable_autonext():
+    seconds = 1/4
+    if app_client._client.firmware.device == 'stax': # Stax Speculos is slow
+        interval = seconds * 3
+    else:
+        interval = seconds
+    signal.setitimer(signal.ITIMER_REAL, seconds, interval)
+
+def disable_autonext():
+    signal.setitimer(signal.ITIMER_REAL, 0, 0)
+
+
+def process_file(aclient: EthAppClient,
+                 input_file_path: str,
+                 filtering_file_path = None,
+                 autonext: Callable = None) -> bool:
     global sig_ctx
     global app_client
+    global autonext_handler
 
     app_client = aclient
     with open(input_file_path, "r") as data:
@@ -322,23 +353,31 @@ def process_file(aclient: EthereumClient, input_file_path: str, filtering_file_p
         domain = data_json["domain"]
         message = data_json["message"]
 
+        if autonext:
+            autonext_handler = autonext
+            signal.signal(signal.SIGALRM, next_timeout)
+
         if filtering_file_path:
             init_signature_context(types, domain)
             filtr = read_filtering_file(domain, message, filtering_file_path)
 
         # send types definition
         for key in types.keys():
-            app_client.eip712_send_struct_def_struct_name(key)
+            with app_client.eip712_send_struct_def_struct_name(key):
+                pass
             for f in types[key]:
                 (f["type"], f["enum"], f["typesize"], f["array_lvls"]) = \
                 send_struct_def_field(f["type"], f["name"])
 
         if filtering_file_path:
-            app_client.eip712_filtering_activate()
+            with app_client.eip712_filtering_activate():
+                pass
             prepare_filtering(filtr, message)
 
         # send domain implementation
-        app_client.eip712_send_struct_impl_root_struct(domain_typename)
+        with app_client.eip712_send_struct_impl_root_struct(domain_typename):
+            enable_autonext()
+        disable_autonext()
         if not send_struct_impl(types, domain, domain_typename):
             return False
 
@@ -349,7 +388,9 @@ def process_file(aclient: EthereumClient, input_file_path: str, filtering_file_p
                 send_filtering_message_info(domain["name"], len(filtering_paths))
 
         # send message implementation
-        app_client.eip712_send_struct_impl_root_struct(message_typename)
+        with app_client.eip712_send_struct_impl_root_struct(message_typename):
+            enable_autonext()
+        disable_autonext()
         if not send_struct_impl(types, message, message_typename):
             return False
 
diff --git a/tests/ragger/eip712/input_files/13-empty_arrays-data.json b/tests/ragger/eip712/input_files/13-empty_arrays-data.json
new file mode 100644
index 000000000..7a1f93943
--- /dev/null
+++ b/tests/ragger/eip712/input_files/13-empty_arrays-data.json
@@ -0,0 +1,37 @@
+{
+    "domain": {
+        "chainId": 5,
+        "name": "Empty Arrays",
+        "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
+        "version": "1"
+    },
+    "message": {
+        "list1": [],
+        "list2": [],
+        "list3": [
+            [
+                "1",
+                "2"
+            ],
+            [],
+            [
+                "3",
+                "4"
+            ]
+        ]
+    },
+    "primaryType": "Struct",
+    "types": {
+        "EIP712Domain": [
+            { "name": "name", "type": "string" },
+            { "name": "version", "type": "string" },
+            { "name": "chainId", "type": "uint256" },
+            { "name": "verifyingContract", "type": "address" }
+        ],
+        "Struct": [
+            { "name": "list1", "type": "EIP712Domain[]" },
+            { "name": "list2", "type": "uint8[]" },
+            { "name": "list3", "type": "string[][]" }
+        ]
+    }
+}
diff --git a/tests/ragger/eip712/input_files/13-empty_arrays.ini b/tests/ragger/eip712/input_files/13-empty_arrays.ini
new file mode 100644
index 000000000..4784a4884
--- /dev/null
+++ b/tests/ragger/eip712/input_files/13-empty_arrays.ini
@@ -0,0 +1,4 @@
+[signature]
+v = 1b
+r = 5d0635a868602e29366da6328f8fadf2d6a9b4e69ee7a65928e85ca56fb1b515
+s = 257364d6faaf5687edf90c3984f4240b0ce7b2dee55aa1f8f39c32d0d4d8c93d
diff --git a/tests/ragger/requirements.txt b/tests/ragger/requirements.txt
index e408eadea..34213d69f 100644
--- a/tests/ragger/requirements.txt
+++ b/tests/ragger/requirements.txt
@@ -1,4 +1,4 @@
-ragger[speculos]>=1.6.0,<1.7.0
+ragger[speculos]
 pytest
 ecdsa
 simple-rlp
diff --git a/tests/ragger/snapshots/nanosp b/tests/ragger/snapshots/nanosp
deleted file mode 120000
index da13a6af4..000000000
--- a/tests/ragger/snapshots/nanosp
+++ /dev/null
@@ -1,1 +0,0 @@
-nanox/
\ No newline at end of file
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00000.png b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00001.png b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00001.png
new file mode 100644
index 000000000..f9840e3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00002.png b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00002.png
new file mode 100644
index 000000000..6af0ec54b
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00003.png b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00003.png
new file mode 100644
index 000000000..93112b3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00004.png b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00004.png
new file mode 100644
index 000000000..70c1b9a68
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00005.png b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00005.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00005.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00006.png b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00006.png
new file mode 100644
index 000000000..a58590b98
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00006.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00000.png b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00001.png b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00001.png
new file mode 100644
index 000000000..f9840e3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00002.png b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00002.png
new file mode 100644
index 000000000..6a5a9d64a
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00003.png b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00003.png
new file mode 100644
index 000000000..85a797b91
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00004.png b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00004.png
new file mode 100644
index 000000000..70c1b9a68
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00005.png b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00005.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00005.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00006.png b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00006.png
new file mode 100644
index 000000000..a58590b98
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00006.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00000.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00001.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00001.png
new file mode 100644
index 000000000..f9840e3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00002.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00002.png
new file mode 100644
index 000000000..6af0ec54b
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00003.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00003.png
new file mode 100644
index 000000000..70c1b9a68
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00004.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00004.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00005.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00005.png
new file mode 100644
index 000000000..a58590b98
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00005.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00000.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00001.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00001.png
new file mode 100644
index 000000000..f9840e3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00002.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00002.png
new file mode 100644
index 000000000..6af0ec54b
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00003.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00003.png
new file mode 100644
index 000000000..6a5a9d64a
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00004.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00004.png
new file mode 100644
index 000000000..70c1b9a68
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00005.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00005.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00005.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00006.png b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00006.png
new file mode 100644
index 000000000..a58590b98
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00006.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00000.png b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00001.png b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00001.png
new file mode 100644
index 000000000..f9840e3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00002.png b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00002.png
new file mode 100644
index 000000000..639e4214e
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00003.png b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00003.png
new file mode 100644
index 000000000..70c1b9a68
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00004.png b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00004.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00005.png b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00005.png
new file mode 100644
index 000000000..a58590b98
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png
index 6a5a9d64a..6af0ec54b 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png and b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png
index 70c1b9a68..1bcb78761 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png and b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00006.png b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00006.png
index a58590b98..657887225 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00006.png and b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00000.png b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00001.png b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00001.png
new file mode 100644
index 000000000..f9840e3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00002.png b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00002.png
new file mode 100644
index 000000000..6a5a9d64a
Binary files /dev/null and b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00003.png b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00003.png
new file mode 100644
index 000000000..85a797b91
Binary files /dev/null and b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00004.png b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00004.png
new file mode 100644
index 000000000..1bcb78761
Binary files /dev/null and b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00005.png b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00005.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00006.png b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00006.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00003.png b/tests/ragger/snapshots/nanox/domain_name_verbose_False/00003.png
index 70c1b9a68..1bcb78761 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00003.png and b/tests/ragger/snapshots/nanox/domain_name_verbose_False/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00005.png b/tests/ragger/snapshots/nanox/domain_name_verbose_False/00005.png
index a58590b98..657887225 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00005.png and b/tests/ragger/snapshots/nanox/domain_name_verbose_False/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png b/tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png
index 70c1b9a68..1bcb78761 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png and b/tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00006.png b/tests/ragger/snapshots/nanox/domain_name_verbose_True/00006.png
index a58590b98..657887225 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00006.png and b/tests/ragger/snapshots/nanox/domain_name_verbose_True/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00003.png b/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00003.png
index 70c1b9a68..1bcb78761 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00003.png and b/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00005.png b/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00005.png
index a58590b98..657887225 100644
Binary files a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00005.png and b/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00005.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00000.png b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00000.png
new file mode 100644
index 000000000..795ca0c2a
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00000.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00001.png b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00001.png
new file mode 100644
index 000000000..661ea68ef
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00001.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00002.png b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00002.png
new file mode 100644
index 000000000..7f634cc4a
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00002.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00003.png b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00003.png
new file mode 100644
index 000000000..7a05bf7b3
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00003.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00004.png b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00004.png
new file mode 100644
index 000000000..7a05bf7b3
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_non_mainnet/00004.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00000.png b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00000.png
new file mode 100644
index 000000000..795ca0c2a
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00000.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00001.png b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00001.png
new file mode 100644
index 000000000..252785952
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00001.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00002.png b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00002.png
new file mode 100644
index 000000000..592a8aca7
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00002.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00003.png b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00003.png
new file mode 100644
index 000000000..299779759
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00003.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00004.png b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00004.png
new file mode 100644
index 000000000..7a05bf7b3
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_unknown_chain/00004.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00000.png b/tests/ragger/snapshots/stax/domain_name_verbose_False/00000.png
new file mode 100644
index 000000000..795ca0c2a
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_False/00000.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00001.png b/tests/ragger/snapshots/stax/domain_name_verbose_False/00001.png
new file mode 100644
index 000000000..5e0c0a941
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_False/00001.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00002.png b/tests/ragger/snapshots/stax/domain_name_verbose_False/00002.png
new file mode 100644
index 000000000..7f634cc4a
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_False/00002.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00003.png b/tests/ragger/snapshots/stax/domain_name_verbose_False/00003.png
new file mode 100644
index 000000000..7a05bf7b3
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_False/00003.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00000.png b/tests/ragger/snapshots/stax/domain_name_verbose_True/00000.png
new file mode 100644
index 000000000..795ca0c2a
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_True/00000.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00001.png b/tests/ragger/snapshots/stax/domain_name_verbose_True/00001.png
new file mode 100644
index 000000000..ad8f07755
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_True/00001.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00002.png b/tests/ragger/snapshots/stax/domain_name_verbose_True/00002.png
new file mode 100644
index 000000000..e64dacc0f
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_True/00002.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00003.png b/tests/ragger/snapshots/stax/domain_name_verbose_True/00003.png
new file mode 100644
index 000000000..299779759
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_True/00003.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00004.png b/tests/ragger/snapshots/stax/domain_name_verbose_True/00004.png
new file mode 100644
index 000000000..7a05bf7b3
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_verbose_True/00004.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00000.png b/tests/ragger/snapshots/stax/domain_name_wrong_addr/00000.png
new file mode 100644
index 000000000..795ca0c2a
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_wrong_addr/00000.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00001.png b/tests/ragger/snapshots/stax/domain_name_wrong_addr/00001.png
new file mode 100644
index 000000000..3e505d39d
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_wrong_addr/00001.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00002.png b/tests/ragger/snapshots/stax/domain_name_wrong_addr/00002.png
new file mode 100644
index 000000000..7f634cc4a
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_wrong_addr/00002.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00003.png b/tests/ragger/snapshots/stax/domain_name_wrong_addr/00003.png
new file mode 100644
index 000000000..7a05bf7b3
Binary files /dev/null and b/tests/ragger/snapshots/stax/domain_name_wrong_addr/00003.png differ
diff --git a/tests/ragger/test_domain_name.py b/tests/ragger/test_domain_name.py
index 317f72da4..f137610db 100644
--- a/tests/ragger/test_domain_name.py
+++ b/tests/ragger/test_domain_name.py
@@ -1,7 +1,11 @@
 import pytest
 from ragger.error import ExceptionRAPDU
-from app.client import EthereumClient, StatusWord
-from app.setting import SettingType
+from ragger.firmware import Firmware
+from ragger.backend import BackendInterface
+from ragger.navigator import Navigator, NavInsID
+from app.client import EthAppClient, StatusWord, ROOT_SCREENSHOT_PATH
+from app.settings import SettingID, settings_toggle
+import app.response_parser as ResponseParser
 import struct
 
 # Values used across all tests
@@ -20,108 +24,211 @@
 def verbose(request) -> bool:
     return request.param
 
-def common(app_client: EthereumClient) -> int:
+def common(app_client: EthAppClient) -> int:
     if app_client._client.firmware.device == "nanos":
         pytest.skip("Not supported on LNS")
-    return app_client.get_challenge()
+    with app_client.get_challenge():
+        pass
+    return ResponseParser.challenge(app_client.response().data)
 
 
-def test_send_fund(app_client: EthereumClient, verbose: bool):
+def test_send_fund(firmware: Firmware,
+                   backend: BackendInterface,
+                   navigator: Navigator,
+                   test_name: str,
+                   verbose: bool):
+    app_client = EthAppClient(backend)
     challenge = common(app_client)
 
     if verbose:
-        app_client.settings_set({
-            SettingType.VERBOSE_ENS: True
-        })
-
-    app_client.provide_domain_name(challenge, NAME, ADDR)
-
-    app_client.send_fund(BIP32_PATH,
-                         NONCE,
-                         GAS_PRICE,
-                         GAS_LIMIT,
-                         ADDR,
-                         AMOUNT,
-                         CHAIN_ID,
-                         "domain_name_verbose_" + str(verbose))
-
-def test_send_fund_wrong_challenge(app_client: EthereumClient):
+        settings_toggle(firmware, navigator, [SettingID.VERBOSE_ENS])
+
+    with app_client.provide_domain_name(challenge, NAME, ADDR):
+        pass
+
+    with app_client.send_fund(BIP32_PATH,
+                              NONCE,
+                              GAS_PRICE,
+                              GAS_LIMIT,
+                              ADDR,
+                              AMOUNT,
+                              CHAIN_ID):
+        moves = list()
+        if firmware.device.startswith("nano"):
+            moves += [ NavInsID.RIGHT_CLICK ] * 4
+            if verbose:
+                moves += [ NavInsID.RIGHT_CLICK ]
+            moves += [ NavInsID.BOTH_CLICK ]
+        else:
+            moves += [ NavInsID.USE_CASE_REVIEW_TAP ] * 2
+            if verbose:
+                moves += [ NavInsID.USE_CASE_REVIEW_TAP ]
+            moves += [ NavInsID.USE_CASE_REVIEW_CONFIRM ]
+        navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
+                                       "domain_name_verbose_" + str(verbose),
+                                       moves)
+
+
+def test_send_fund_wrong_challenge(firmware: Firmware,
+                                   backend: BackendInterface,
+                                   navigator: Navigator):
+    app_client = EthAppClient(backend)
     caught = False
     challenge = common(app_client)
 
     try:
-        app_client.provide_domain_name(~challenge & 0xffffffff, NAME, ADDR)
+        with app_client.provide_domain_name(~challenge & 0xffffffff, NAME, ADDR):
+            pass
     except ExceptionRAPDU as e:
         assert e.status == StatusWord.INVALID_DATA
     else:
         assert False # An exception should have been raised
 
-def test_send_fund_wrong_addr(app_client: EthereumClient):
+
+def test_send_fund_wrong_addr(firmware: Firmware,
+                              backend: BackendInterface,
+                              navigator: Navigator,
+                              test_name: str):
+    app_client = EthAppClient(backend)
     challenge = common(app_client)
 
-    app_client.provide_domain_name(challenge, NAME, ADDR)
+    with app_client.provide_domain_name(challenge, NAME, ADDR):
+        pass
 
     addr = bytearray(ADDR)
     addr.reverse()
 
-    app_client.send_fund(BIP32_PATH,
-                         NONCE,
-                         GAS_PRICE,
-                         GAS_LIMIT,
-                         addr,
-                         AMOUNT,
-                         CHAIN_ID,
-                         "domain_name_wrong_addr")
-
-def test_send_fund_non_mainnet(app_client: EthereumClient):
+    with app_client.send_fund(BIP32_PATH,
+                              NONCE,
+                              GAS_PRICE,
+                              GAS_LIMIT,
+                              addr,
+                              AMOUNT,
+                              CHAIN_ID):
+        moves = list()
+        if firmware.device.startswith("nano"):
+            moves += [ NavInsID.RIGHT_CLICK ] * 4
+            moves += [ NavInsID.BOTH_CLICK ]
+        else:
+            moves += [ NavInsID.USE_CASE_REVIEW_TAP ] * 2
+            moves += [ NavInsID.USE_CASE_REVIEW_CONFIRM ]
+        navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
+                                       "domain_name_wrong_addr",
+                                       moves)
+
+
+def test_send_fund_non_mainnet(firmware: Firmware,
+                               backend: BackendInterface,
+                               navigator: Navigator,
+                               test_name: str):
+    app_client = EthAppClient(backend)
     challenge = common(app_client)
 
-    app_client.provide_domain_name(challenge, NAME, ADDR)
-
-    app_client.send_fund(BIP32_PATH,
-                         NONCE,
-                         GAS_PRICE,
-                         GAS_LIMIT,
-                         ADDR,
-                         AMOUNT,
-                         5,
-                         "domain_name_non_mainnet")
+    with app_client.provide_domain_name(challenge, NAME, ADDR):
+        pass
+
+    with app_client.send_fund(BIP32_PATH,
+                              NONCE,
+                              GAS_PRICE,
+                              GAS_LIMIT,
+                              ADDR,
+                              AMOUNT,
+                              5):
+        moves = list()
+        if firmware.device.startswith("nano"):
+            moves += [ NavInsID.RIGHT_CLICK ] * 5
+            moves += [ NavInsID.BOTH_CLICK ]
+        else:
+            moves += [ NavInsID.USE_CASE_REVIEW_TAP ] * 2
+            moves += [ NavInsID.USE_CASE_REVIEW_CONFIRM ]
+        navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
+                                       "domain_name_non_mainnet",
+                                       moves)
+
+
+def test_send_fund_unknown_chain(firmware: Firmware,
+                                 backend: BackendInterface,
+                                 navigator: Navigator,
+                                 test_name: str):
+    app_client = EthAppClient(backend)
+    challenge = common(app_client)
 
-def test_send_fund_domain_too_long(app_client: EthereumClient):
+    with app_client.provide_domain_name(challenge, NAME, ADDR):
+        pass
+
+    with app_client.send_fund(BIP32_PATH,
+                              NONCE,
+                              GAS_PRICE,
+                              GAS_LIMIT,
+                              ADDR,
+                              AMOUNT,
+                              9):
+        moves = list()
+        if firmware.device.startswith("nano"):
+            moves += [ NavInsID.RIGHT_CLICK ] * 5
+            moves += [ NavInsID.BOTH_CLICK ]
+        else:
+            moves += [ NavInsID.USE_CASE_REVIEW_TAP ] * 3
+            moves += [ NavInsID.USE_CASE_REVIEW_CONFIRM ]
+        navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
+                                       "domain_name_unknown_chain",
+                                       moves)
+
+
+def test_send_fund_domain_too_long(firmware: Firmware,
+                                   backend: BackendInterface,
+                                   navigator: Navigator):
+    app_client = EthAppClient(backend)
     challenge = common(app_client)
 
     try:
-        app_client.provide_domain_name(challenge, "ledger" + "0"*25 + ".eth", ADDR)
+        with app_client.provide_domain_name(challenge, "ledger" + "0"*25 + ".eth", ADDR):
+            pass
     except ExceptionRAPDU as e:
         assert e.status == StatusWord.INVALID_DATA
     else:
         assert False # An exception should have been raised
 
-def test_send_fund_domain_invalid_character(app_client: EthereumClient):
+
+def test_send_fund_domain_invalid_character(firmware: Firmware,
+                                            backend: BackendInterface,
+                                            navigator: Navigator):
+    app_client = EthAppClient(backend)
     challenge = common(app_client)
 
     try:
-        app_client.provide_domain_name(challenge, "l\xe8dger.eth", ADDR)
+        with app_client.provide_domain_name(challenge, "l\xe8dger.eth", ADDR):
+            pass
     except ExceptionRAPDU as e:
         assert e.status == StatusWord.INVALID_DATA
     else:
         assert False # An exception should have been raised
 
-def test_send_fund_uppercase(app_client: EthereumClient):
+
+def test_send_fund_uppercase(firmware: Firmware,
+                             backend: BackendInterface,
+                             navigator: Navigator):
+    app_client = EthAppClient(backend)
     challenge = common(app_client)
 
     try:
-        app_client.provide_domain_name(challenge, NAME.upper(), ADDR)
+        with app_client.provide_domain_name(challenge, NAME.upper(), ADDR):
+            pass
     except ExceptionRAPDU as e:
         assert e.status == StatusWord.INVALID_DATA
     else:
         assert False # An exception should have been raised
 
-def test_send_fund_domain_non_ens(app_client: EthereumClient):
+
+def test_send_fund_domain_non_ens(firmware: Firmware,
+                                  backend: BackendInterface,
+                                  navigator: Navigator):
+    app_client = EthAppClient(backend)
     challenge = common(app_client)
 
     try:
-        app_client.provide_domain_name(challenge, "ledger.hte", ADDR)
+        with app_client.provide_domain_name(challenge, "ledger.hte", ADDR):
+            pass
     except ExceptionRAPDU as e:
         assert e.status == StatusWord.INVALID_DATA
     else:
diff --git a/tests/ragger/test_eip712.py b/tests/ragger/test_eip712.py
index 29cb84394..6ff0bc7b3 100644
--- a/tests/ragger/test_eip712.py
+++ b/tests/ragger/test_eip712.py
@@ -2,10 +2,17 @@
 import os
 import fnmatch
 from typing import List
-from app.client import EthereumClient, SettingType
+from ragger.firmware import Firmware
+from ragger.backend import BackendInterface
+from ragger.navigator import Navigator, NavInsID
+from app.client import EthAppClient
+from app.settings import SettingID, settings_toggle
 from eip712 import InputData
 from pathlib import Path
 from configparser import ConfigParser
+import app.response_parser as ResponseParser
+from functools import partial
+import time
 
 BIP32_PATH = "m/44'/60'/0'/0/0"
 
@@ -30,19 +37,52 @@ def filtering(request) -> bool:
     return request.param
 
 
-def test_eip712_legacy(app_client: EthereumClient):
-    v, r, s = app_client.eip712_sign_legacy(
-        BIP32_PATH,
-        bytes.fromhex('6137beb405d9ff777172aa879e33edb34a1460e701802746c5ef96e741710e59'),
-        bytes.fromhex('eb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8')
-    )
+def test_eip712_legacy(firmware: Firmware,
+                       backend: BackendInterface,
+                       navigator: Navigator):
+    app_client = EthAppClient(backend)
+    with app_client.eip712_sign_legacy(
+            BIP32_PATH,
+            bytes.fromhex('6137beb405d9ff777172aa879e33edb34a1460e701802746c5ef96e741710e59'),
+            bytes.fromhex('eb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8')):
+        moves = list()
+        if firmware.device.startswith("nano"):
+            moves += [ NavInsID.RIGHT_CLICK ]
+            if firmware.device == "nanos":
+                screens_per_hash = 4
+            else:
+                screens_per_hash = 2
+            moves += [ NavInsID.RIGHT_CLICK ] * screens_per_hash * 2
+            moves += [ NavInsID.BOTH_CLICK ]
+        else:
+            moves += [ NavInsID.USE_CASE_REVIEW_TAP ] * 2
+            moves += [ NavInsID.USE_CASE_REVIEW_CONFIRM ]
+        navigator.navigate(moves)
+
+    v, r, s = ResponseParser.signature(app_client.response().data)
 
     assert v == bytes.fromhex("1c")
     assert r == bytes.fromhex("ea66f747173762715751c889fea8722acac3fc35db2c226d37a2e58815398f64")
     assert s == bytes.fromhex("52d8ba9153de9255da220ffd36762c0b027701a3b5110f0a765f94b16a9dfb55")
 
-def test_eip712_new(app_client: EthereumClient, input_file: Path, verbose: bool, filtering: bool):
-    if app_client._client.firmware.device == "nanos":
+
+def autonext(fw: Firmware, nav: Navigator):
+    moves = list()
+    if fw.device.startswith("nano"):
+        moves = [ NavInsID.RIGHT_CLICK ]
+    else:
+        moves = [ NavInsID.USE_CASE_REVIEW_TAP ]
+    nav.navigate(moves, screen_change_before_first_instruction=False, screen_change_after_last_instruction=False)
+
+
+def test_eip712_new(firmware: Firmware,
+                    backend: BackendInterface,
+                    navigator: Navigator,
+                    input_file: Path,
+                    verbose: bool,
+                    filtering: bool):
+    app_client = EthAppClient(backend)
+    if firmware.device == "nanos":
         pytest.skip("Not supported on LNS")
     else:
         test_path = "%s/%s" % (input_file.parent, "-".join(input_file.stem.split("-")[:-1]))
@@ -63,12 +103,25 @@ def test_eip712_new(app_client: EthereumClient, input_file: Path, verbose: bool,
 
         if not filtering or Path(filter_file).is_file():
             if verbose:
-                app_client.settings_set({
-                    SettingType.VERBOSE_EIP712: True
-                })
-
-            assert InputData.process_file(app_client, input_file, filter_file) == True
-            v, r, s = app_client.eip712_sign_new(BIP32_PATH)
+                settings_toggle(firmware, navigator, [SettingID.VERBOSE_EIP712])
+
+            assert InputData.process_file(app_client,
+                                          input_file,
+                                          filter_file,
+                                          partial(autonext, firmware, navigator)) == True
+            with app_client.eip712_sign_new(BIP32_PATH, verbose):
+                time.sleep(0.5) # tight on timing, needed by the CI otherwise might fail sometimes
+                moves = list()
+                if firmware.device.startswith("nano"):
+                    if not verbose and not filtering: # need to skip the message hash
+                        moves = [ NavInsID.RIGHT_CLICK ] * 2
+                    moves += [ NavInsID.BOTH_CLICK ]
+                else:
+                    if not verbose and not filtering: # need to skip the message hash
+                        moves += [ NavInsID.USE_CASE_REVIEW_TAP ]
+                    moves += [ NavInsID.USE_CASE_REVIEW_CONFIRM ]
+                navigator.navigate(moves)
+            v, r, s = ResponseParser.signature(app_client.response().data)
             #print("[signature]")
             #print("v = %s" % (v.hex()))
             #print("r = %s" % (r.hex()))
diff --git a/tests/speculos/README.md b/tests/speculos/README.md
index c3bb346cb..68d146878 100644
--- a/tests/speculos/README.md
+++ b/tests/speculos/README.md
@@ -11,9 +11,8 @@ These tests are implemented in Python with the `SpeculosClient` interface which
 Python dependencies are listed in [requirements.txt](requirements.txt)
 
 ```shell
-python3 -m pip install --extra-index-url https://test.pypi.org/simple/ -r requirements.txt
+python3 -m pip install -r requirements.txt
 ```
-> The extra index allows to fetch the latest version of Speculos.
 
 ## Usage
 
@@ -47,4 +46,4 @@ pytest --model nanox --path ./elfs/nanox.elf
 
 # Execute specific test:
 pytest --model nanox --path ./elfs/nanox.elf test_pubkey_cmd.py
-```
\ No newline at end of file
+```
diff --git a/tests/speculos/test_configuration_cmd.py b/tests/speculos/test_configuration_cmd.py
index 1d848391b..8027b2cf8 100644
--- a/tests/speculos/test_configuration_cmd.py
+++ b/tests/speculos/test_configuration_cmd.py
@@ -1,10 +1,10 @@
 
 def test_configuration(cmd):
     if cmd.model == "nanos":
-        assert cmd.get_configuration() == (14, 1, 10, 2)
+        assert cmd.get_configuration() == (14, 1, 10, 3)
 
     if cmd.model == "nanox":
-        assert cmd.get_configuration() == (14, 1, 10, 2)
+        assert cmd.get_configuration() == (14, 1, 10, 3)
 
     if cmd.model == "nanosp":
-        assert cmd.get_configuration() == (14, 1, 10, 2)
+        assert cmd.get_configuration() == (14, 1, 10, 3)