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

Issue:
Fix EIP-712 NBGL pairs packing
## Description

Uses https://github.com/LedgerHQ/ledger-secure-sdk/pull/787

Snapshots had to be re-generated because of an SDK bump for Stax & Flex in the app-builder, not because of this one-line change.

## Changes include

- [x] 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
- [ ] Other (for changes that might not fit in any category)


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 98ff9eb69..013cb590d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,58 @@ 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.12.0](https://github.com/ledgerhq/app-ethereum/compare/1.11.3...1.12.0) - 2024-09-27
+
+### Added
+
+- Ledger PKI support
+- Added support for swap with calldata (Thorswap / LiFi / ...)
+- (network) PulseChain Testnet
+- The app now provides the derivation path to its plugins
+- Support for Trusted Name V2 payloads
+- EIP-712 filtering on trusted names
+
+### Removed
+
+- (clone) ApothemNetwork
+- (clone) Binance Smart Chain
+- (clone) BTTC
+- (clone) Conflux eSpace
+- (clone) Cube
+- (clone) KardiaChain
+- (clone) Meter
+- (clone) MultiVAC
+- (clone) OKXChain
+- (clone) POA
+- (clone) Polygon
+- (clone) Shyft
+
+### Fixed
+
+- (network) Apothemnetwork ticker
+- Missing error handling on EIP-712, which could lead to a crash of the app
+- EIP-712 filtering on fields within an empty array (requires client support with a new APDU)
+- EIP-712 amount-join filtering with missing token information
+- EIP-712 UI-code overflow on Stax which could lead to a crash of the app
+
+### Changed
+
+- (clone) Astar Polkadot EVM, removed Ethereum derivation path
+- (clone) EnergyWebChain, removed Ethereum derivation path
+- (clone) Ethereum Classic, removed Ethereum derivation path
+- (clone) Moonbeam, removed Ethereum derivation path
+- (clone) Moonriver, removed Ethereum derivation path
+- (clone) Oasys, removed Ethereum derivation path
+- (clone) Shiden EVM, removed Ethereum derivation path
+- (clone) Songbird, removed Ethereum derivation path
+- (clone) TecraCoin, removed Ethereum derivation path
+- (clone) TecraTestnet, removed Ethereum derivation path
+- (clone) Volta, removed Ethereum derivation path
+- (clone) XDC Network, removed Ethereum derivation path
+- Now the app sends back its response immediately instead of after the Transaction/Message signed/rejected screen on Stax & Flex
+- Added blind-signing friction to EIP-712 v0 & unfiltered flows
+- EIP-712 unfiltered flow now defaults to raw/verbose mode on Stax & Flex, but adds a skip button
+
 ## [1.11.3](https://github.com/ledgerhq/app-ethereum/compare/1.11.2...1.11.3) - 2024-09-04
 
 ### Changed
diff --git a/Makefile b/Makefile
index 28e78e2c9..9c99d7877 100644
--- a/Makefile
+++ b/Makefile
@@ -27,8 +27,6 @@ include $(BOLOS_SDK)/Makefile.defines
 
 ifeq ($(CHAIN),)
     CHAIN = ethereum
-    # Temporary definition to ensure VSCode extension works... To be cleaned later
-    APPNAME = Ethereum
 endif
 
 SUPPORTED_CHAINS = $(shell find makefile_conf/chain/ -type f -name '*.mk'| sed 's/.*\/\(.*\).mk/\1/g' | sort)
@@ -38,8 +36,8 @@ endif
 include ./makefile_conf/chain/$(CHAIN).mk
 
 APPVERSION_M = 1
-APPVERSION_N = 11
-APPVERSION_P = 3
+APPVERSION_N = 12
+APPVERSION_P = 0
 APPVERSION = $(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
 
 # Application source files
@@ -51,9 +49,6 @@ else
 endif
 APP_SOURCE_FILES += $(filter-out ./ethereum-plugin-sdk/src/main.c, $(wildcard ./ethereum-plugin-sdk/src/*.c))
 INCLUDES_PATH += ./ethereum-plugin-sdk/src
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/crypto_helpers.c
-APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/format.c
-INCLUDES_PATH += ${BOLOS_SDK}/lib_standard_app
 
 ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_STAX TARGET_FLEX))
 NETWORK_ICONS_FILE = $(GEN_SRC_DIR)/net_icons.gen.c
@@ -80,6 +75,9 @@ ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_STAX TARGET_FLEX))
     DEFINES += ICONGLYPH_SMALL=C_chain_$(CHAIN_ID)
 endif
 
+# Don't define plugin function in the plugin SDK
+DEFINES += IS_NOT_A_PLUGIN
+
 
 # Application allowed derivation curves.
 # Possibles curves are: secp256k1, secp256r1, ed25519 and bls12381g1
@@ -141,7 +139,7 @@ ENABLE_NBGL_QRCODE = 1
 ########################################
 # These advanced settings allow to disable some feature that are by
 # default enabled in the SDK `Makefile.standard_app`.
-DISABLE_STANDARD_APP_FILES = 1
+#DISABLE_STANDARD_APP_FILES = 1
 #DISABLE_DEFAULT_IO_SEPROXY_BUFFER_SIZE = 1 # To allow custom size declaration
 #DISABLE_STANDARD_APP_DEFINES = 1 # Will set all the following disablers
 #DISABLE_STANDARD_SNPRINTF = 1
@@ -155,7 +153,7 @@ DISABLE_STANDARD_APP_FILES = 1
 #        Main app configuration        #
 ########################################
 
-DEFINES += CHAINID_COINNAME=\"$(TICKER)\" CHAIN_ID=$(CHAIN_ID)
+DEFINES += APP_TICKER=\"$(TICKER)\" APP_CHAIN_ID=$(CHAIN_ID)
 
 # Enabled Features #
 include makefile_conf/features.mk
diff --git a/client/src/ledger_app_clients/ethereum/client.py b/client/src/ledger_app_clients/ethereum/client.py
index a09bd41ce..9b6a4de89 100644
--- a/client/src/ledger_app_clients/ethereum/client.py
+++ b/client/src/ledger_app_clients/ethereum/client.py
@@ -1,6 +1,9 @@
 import rlp
+import struct
 from enum import IntEnum
 from ragger.backend import BackendInterface
+from ragger.firmware import Firmware
+from ragger.error import ExceptionRAPDU
 from ragger.utils import RAPDU
 from typing import Optional
 
@@ -22,24 +25,87 @@ class StatusWord(IntEnum):
     CONDITION_NOT_SATISFIED = 0x6985
     REF_DATA_NOT_FOUND = 0x6a88
     EXCEPTION_OVERFLOW = 0x6807
+    NOT_IMPLEMENTED = 0x911c
 
 
-class DomainNameTag(IntEnum):
-    STRUCTURE_TYPE = 0x01
-    STRUCTURE_VERSION = 0x02
+class TrustedNameType(IntEnum):
+    ACCOUNT = 0x01
+    CONTRACT = 0x02
+    NFT = 0x03
+
+
+class TrustedNameSource(IntEnum):
+    LAB = 0x00
+    CAL = 0x01
+    ENS = 0x02
+    UD = 0x03
+    FN = 0x04
+    DNS = 0x05
+
+
+class TrustedNameTag(IntEnum):
+    STRUCT_TYPE = 0x01
+    STRUCT_VERSION = 0x02
+    NOT_VALID_AFTER = 0x10
     CHALLENGE = 0x12
     SIGNER_KEY_ID = 0x13
     SIGNER_ALGO = 0x14
     SIGNATURE = 0x15
-    DOMAIN_NAME = 0x20
+    NAME = 0x20
     COIN_TYPE = 0x21
     ADDRESS = 0x22
+    CHAIN_ID = 0x23
+    NAME_TYPE = 0x70
+    NAME_SOURCE = 0x71
+    NFT_ID = 0x72
+
+
+class PKIPubKeyUsage(IntEnum):
+    PUBKEY_USAGE_GENUINE_CHECK = 0x01
+    PUBKEY_USAGE_EXCHANGE_PAYLOAD = 0x02
+    PUBKEY_USAGE_NFT_METADATA = 0x03
+    PUBKEY_USAGE_TRUSTED_NAME = 0x04
+    PUBKEY_USAGE_BACKUP_PROVIDER = 0x05
+    PUBKEY_USAGE_RECOVER_ORCHESTRATOR = 0x06
+    PUBKEY_USAGE_PLUGIN_METADATA = 0x07
+    PUBKEY_USAGE_COIN_META = 0x08
+    PUBKEY_USAGE_SEED_ID_AUTH = 0x09
+
+
+class PKIClient:
+    _CLA: int = 0xB0
+    _INS: int = 0x06
+
+    def __init__(self, client: BackendInterface) -> None:
+        self._client = client
+
+    def send_certificate(self, p1: PKIPubKeyUsage, payload: bytes) -> RAPDU:
+        try:
+            response = self.send_raw(p1, payload)
+            assert response.status == StatusWord.OK
+        except ExceptionRAPDU as err:
+            if err.status == StatusWord.NOT_IMPLEMENTED:
+                print("Ledger-PKI APDU not yet implemented. Legacy path will be used")
+
+    def send_raw(self, p1: PKIPubKeyUsage, payload: bytes) -> RAPDU:
+        header = bytearray()
+        header.append(self._CLA)
+        header.append(self._INS)
+        header.append(p1)
+        header.append(0x00)
+        header.append(len(payload))
+        return self._client.exchange_raw(header + payload)
 
 
 class EthAppClient:
     def __init__(self, client: BackendInterface):
         self._client = client
+        self._firmware = client.firmware
         self._cmd_builder = CommandBuilder()
+        self._pki_client: Optional[PKIClient] = None
+        if self._firmware != Firmware.NANOS:
+            # LedgerPKI not supported on Nanos
+            self._pki_client = PKIClient(self._client)
 
     def _exchange_async(self, payload: bytes):
         return self._client.exchange_async_raw(payload)
@@ -101,25 +167,42 @@ def eip712_sign_legacy(self,
     def eip712_filtering_activate(self):
         return self._exchange_async(self._cmd_builder.eip712_filtering_activate())
 
+    def eip712_filtering_discarded_path(self, path: str):
+        return self._exchange(self._cmd_builder.eip712_filtering_discarded_path(path))
+
     def eip712_filtering_message_info(self, name: str, filters_count: int, sig: bytes):
         return self._exchange_async(self._cmd_builder.eip712_filtering_message_info(name,
                                                                                     filters_count,
                                                                                     sig))
 
-    def eip712_filtering_amount_join_token(self, token_idx: int, sig: bytes):
+    def eip712_filtering_amount_join_token(self, token_idx: int, sig: bytes, discarded: bool):
         return self._exchange_async(self._cmd_builder.eip712_filtering_amount_join_token(token_idx,
-                                                                                         sig))
+                                                                                         sig,
+                                                                                         discarded))
 
-    def eip712_filtering_amount_join_value(self, token_idx: int, name: str, sig: bytes):
+    def eip712_filtering_amount_join_value(self, token_idx: int, name: str, sig: bytes, discarded: bool):
         return self._exchange_async(self._cmd_builder.eip712_filtering_amount_join_value(token_idx,
                                                                                          name,
-                                                                                         sig))
-
-    def eip712_filtering_datetime(self, name: str, sig: bytes):
-        return self._exchange_async(self._cmd_builder.eip712_filtering_datetime(name, sig))
-
-    def eip712_filtering_raw(self, name: str, sig: bytes):
-        return self._exchange_async(self._cmd_builder.eip712_filtering_raw(name, sig))
+                                                                                         sig,
+                                                                                         discarded))
+
+    def eip712_filtering_datetime(self, name: str, sig: bytes, discarded: bool):
+        return self._exchange_async(self._cmd_builder.eip712_filtering_datetime(name, sig, discarded))
+
+    def eip712_filtering_trusted_name(self,
+                                      name: str,
+                                      name_type: list[int],
+                                      name_source: list[int],
+                                      sig: bytes,
+                                      discarded: bool):
+        return self._exchange_async(self._cmd_builder.eip712_filtering_trusted_name(name,
+                                                                                    name_type,
+                                                                                    name_source,
+                                                                                    sig,
+                                                                                    discarded))
+
+    def eip712_filtering_raw(self, name: str, sig: bytes, discarded: bool):
+        return self._exchange_async(self._cmd_builder.eip712_filtering_raw(name, sig, discarded))
 
     def sign(self,
              bip32_path: str,
@@ -167,23 +250,64 @@ def perform_privacy_operation(self,
                                                                           bip32_path,
                                                                           pubkey))
 
-    def provide_domain_name(self, challenge: int, name: str, addr: bytes) -> RAPDU:
-        payload = format_tlv(DomainNameTag.STRUCTURE_TYPE, 3)  # TrustedDomainName
-        payload += format_tlv(DomainNameTag.STRUCTURE_VERSION, 1)
-        payload += format_tlv(DomainNameTag.SIGNER_KEY_ID, 0)  # test key
-        payload += format_tlv(DomainNameTag.SIGNER_ALGO, 1)  # secp256k1
-        payload += format_tlv(DomainNameTag.CHALLENGE, challenge)
-        payload += format_tlv(DomainNameTag.COIN_TYPE, 0x3c)  # ETH in slip-44
-        payload += format_tlv(DomainNameTag.DOMAIN_NAME, name)
-        payload += format_tlv(DomainNameTag.ADDRESS, addr)
-        payload += format_tlv(DomainNameTag.SIGNATURE,
-                              sign_data(Key.DOMAIN_NAME, payload))
-
-        chunks = self._cmd_builder.provide_domain_name(payload)
+    def _provide_trusted_name_common(self, payload: bytes) -> RAPDU:
+        if self._pki_client is None:
+            print(f"Ledger-PKI Not supported on '{self._firmware.name}'")
+        else:
+            # pylint: disable=line-too-long
+            if self._firmware == Firmware.NANOSP:
+                cert_apdu = "01010102010210040102000011040000000212010013020002140101160400000000200b446f6d61696e5f4e616d6530020007310108320121332102b91fbec173e3ba4a714e014ebc827b6f899a9fa7f4ac769cde284317a00f4f653401013501031546304402201b5188f5af5cd4d40d2e5eee85609323ee129b789082d079644c89c0df9b6ce0022076c5d26bb5c8db8ab02771ecd577f63f68eaf1c90523173f161f9c12f6e978bd"  # noqa: E501
+            elif self._firmware == Firmware.NANOX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F653401013501021546304402202CD052029B756890F0C56713409C58C24785FEFFD1A997E9C840A7BDB176B512022059A30E04E491CD27BD1DA1B5CB810CF8E4EAE67F6406F054FDFC371F7EB9F2C4"  # noqa: E501
+            elif self._firmware == Firmware.STAX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154630440220741DB4E738749D4188436419B20B9AEF8F07581312A9B3C9BAA3F3E879690F6002204C4A3510569247777BC43DB830D129ACA8985B88552E2E234E14D8AA2863026B"  # noqa: E501
+            elif self._firmware == Firmware.FLEX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350105154730450221008B6BBCE1716C0A06F110C77FE181F8395D1692441459A106411463F01A45D4A7022044AB69037E6FA9D1D1A409E00B202C2D4451D464C8E5D4962D509FE63153FE93"  # noqa: E501
+            # pylint: enable=line-too-long
+
+            self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu))
+        payload += format_tlv(TrustedNameTag.STRUCT_TYPE, 3)  # TrustedName
+        payload += format_tlv(TrustedNameTag.SIGNER_KEY_ID, 0)  # test key
+        payload += format_tlv(TrustedNameTag.SIGNER_ALGO, 1)  # secp256k1
+        payload += format_tlv(TrustedNameTag.SIGNATURE,
+                              sign_data(Key.TRUSTED_NAME, payload))
+        chunks = self._cmd_builder.provide_trusted_name(payload)
         for chunk in chunks[:-1]:
             self._exchange(chunk)
         return self._exchange(chunks[-1])
 
+    def provide_trusted_name_v1(self, addr: bytes, name: str, challenge: int) -> RAPDU:
+        payload = format_tlv(TrustedNameTag.STRUCT_VERSION, 1)
+        payload += format_tlv(TrustedNameTag.CHALLENGE, challenge)
+        payload += format_tlv(TrustedNameTag.COIN_TYPE, 0x3c)  # ETH in slip-44
+        payload += format_tlv(TrustedNameTag.NAME, name)
+        payload += format_tlv(TrustedNameTag.ADDRESS, addr)
+        return self._provide_trusted_name_common(payload)
+
+    def provide_trusted_name_v2(self,
+                                addr: bytes,
+                                name: str,
+                                name_type: TrustedNameType,
+                                name_source: TrustedNameSource,
+                                chain_id: int,
+                                nft_id: Optional[int] = None,
+                                challenge: Optional[int] = None,
+                                not_valid_after: Optional[tuple[int]] = None) -> RAPDU:
+        payload = format_tlv(TrustedNameTag.STRUCT_VERSION, 2)
+        payload += format_tlv(TrustedNameTag.NAME, name)
+        payload += format_tlv(TrustedNameTag.ADDRESS, addr)
+        payload += format_tlv(TrustedNameTag.NAME_TYPE, name_type)
+        payload += format_tlv(TrustedNameTag.NAME_SOURCE, name_source)
+        payload += format_tlv(TrustedNameTag.CHAIN_ID, chain_id)
+        if nft_id is not None:
+            payload += format_tlv(TrustedNameTag.NFT_ID, nft_id)
+        if challenge is not None:
+            payload += format_tlv(TrustedNameTag.CHALLENGE, challenge)
+        if not_valid_after is not None:
+            assert len(not_valid_after) == 3
+            payload += format_tlv(TrustedNameTag.NOT_VALID_AFTER, struct.pack("BBB", *not_valid_after))
+        return self._provide_trusted_name_common(payload)
+
     def set_plugin(self,
                    plugin_name: str,
                    contract_addr: bytes,
@@ -194,6 +318,23 @@ def set_plugin(self,
                    key_id: int = 2,
                    algo_id: int = 1,
                    sig: Optional[bytes] = None) -> RAPDU:
+
+        if self._pki_client is None:
+            print(f"Ledger-PKI Not supported on '{self._firmware.name}'")
+        else:
+            # pylint: disable=line-too-long
+            if self._firmware == Firmware.NANOSP:
+                cert_apdu = "01010102010210040102000011040000000212010013020002140101160400000000200A53657420506C7567696E30020003310107320121332103C055BC4ECF055E2D85085D35127A3DE6705C7F885055CD7071E87671BF191FE3340101350103154630440220401824348DA0E435C9BF16C3591665CFA1B7D8E729971BE884027E02BD3C35A102202289EE207B73D98E9E6110CC143EB929F03B99D54C63023C99561D3CE164D30F"  # noqa: E501
+            elif self._firmware == Firmware.NANOX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200A53657420506C7567696E30020003310107320121332103C055BC4ECF055E2D85085D35127A3DE6705C7F885055CD7071E87671BF191FE334010135010215473045022100E657DE255F954779E14D281E2E739D89DEF2E943B7FD4B4AFE49CF4FF7E1D84F022057F29C9AEA8FAA25C8438FDEE85C6DABF270E5CEC1655F17F2D9A6ADCD3ADC0E"  # noqa: E501
+            elif self._firmware == Firmware.STAX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200A53657420506C7567696E30020003310107320121332103C055BC4ECF055E2D85085D35127A3DE6705C7F885055CD7071E87671BF191FE334010135010415473045022100B8AF9667C190B60BF350D8F8CA66A4BCEA22BF47D757CB7F88F8D16C7794BCDC02205F7D6C8E9294F73744A82E1062B10FFEB809252682112E71A419EFC78227211B"  # noqa: E501
+            elif self._firmware == Firmware.FLEX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200A53657420506C7567696E30020003310107320121332103C055BC4ECF055E2D85085D35127A3DE6705C7F885055CD7071E87671BF191FE334010135010515473045022100F5069D8BCEDCF7CC55273266E3871B09FFCACD084B5753347A809DDDA67E6235022003CE65364BFA96B6FE7A9D8C13EC87B8E727E8B7BF4A63176F5D61AB8F97807E"  # noqa: E501
+            # pylint: enable=line-too-long
+
+            self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_PLUGIN_METADATA, bytes.fromhex(cert_apdu))
+
         if sig is None:
             # Temporarily get a command with an empty signature to extract the payload and
             # compute the signature on it
@@ -227,6 +368,23 @@ def provide_nft_metadata(self,
                              key_id: int = 1,
                              algo_id: int = 1,
                              sig: Optional[bytes] = None) -> RAPDU:
+
+        if self._pki_client is None:
+            print(f"Ledger-PKI Not supported on '{self._firmware.name}'")
+        else:
+            # pylint: disable=line-too-long
+            if self._firmware == Firmware.NANOSP:
+                cert_apdu = "0101010201021004010200001104000000021201001302000214010116040000000020084e46545f496e666f300200043101033201213321023cfb5fb31905f4bd39d9d535a40c26aab51c5d7d3219b28ac942b980fb206cfb34010135010315473045022100d43e142a6639b27a79bc4f021854df48f1bc1e828ac47b105578cb527b69f525022078f6e6b3eb9bb787a0a29e85531ce3512c2d6481e761e840db0fb6b0898911a1"  # noqa: E501
+            elif self._firmware == Firmware.NANOX:
+                cert_apdu = "0101010201021104000000021201001302000214010116040000000020084E46545F496E666F300200043101033201213321023CFB5FB31905F4BD39D9D535A40C26AAB51C5D7D3219B28AC942B980FB206CFB340101350102154730450221009BAE21BB8CBA6F95DDFF86AEEA991D63FA36A469A3071F61BDA8895F1A5F0AC3022061661F95D1513D3FDE81FFEA4B0C6D48ADCB27ED70915EE3ACD16A2A64CDE916"  # noqa: E501
+            elif self._firmware == Firmware.STAX:
+                cert_apdu = "0101010201021104000000021201001302000214010116040000000020084E46545F496E666F300200043101033201213321023CFB5FB31905F4BD39D9D535A40C26AAB51C5D7D3219B28AC942B980FB206CFB3401013501041546304402201DEE04EC830FFDE5C98A708EC6865605FC14FF6105A54BE5230F2B954C673B940220581A0A5E42A7779140963703E43B3BEABE4C69284EDEF00E76BB5875E0810C9B"  # noqa: E501
+            elif self._firmware == Firmware.FLEX:
+                cert_apdu = "0101010201021104000000021201001302000214010116040000000020084E46545F496E666F300200043101033201213321023CFB5FB31905F4BD39D9D535A40C26AAB51C5D7D3219B28AC942B980FB206CFB340101350105154730450221009ABCC7056D54C1B5DBB353178B13850C20521EE6884AA415AA61B329DB1D87F602204E308F273B8D18080184695438577F770524F717E5D08EE20ECBF1BC599F3538"  # noqa: E501
+            # pylint: enable=line-too-long
+
+            self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_NFT_METADATA, bytes.fromhex(cert_apdu))
+
         if sig is None:
             # Temporarily get a command with an empty signature to extract the payload and
             # compute the signature on it
@@ -278,6 +436,23 @@ def provide_token_metadata(self,
                                decimals: int,
                                chain_id: int,
                                sig: Optional[bytes] = None) -> RAPDU:
+
+        if self._pki_client is None:
+            print(f"Ledger-PKI Not supported on '{self._firmware.name}'")
+        else:
+            # pylint: disable=line-too-long
+            if self._firmware == Firmware.NANOSP:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010310040102000015473045022100C15795C2AE41E6FAE6B1362EE1AE216428507D7C1D6939B928559CC7A1F6425C02206139CF2E133DD62F3E00F183E42109C9853AC62B6B70C5079B9A80DBB9D54AB5"  # noqa: E501
+            elif self._firmware == Firmware.NANOX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010215473045022100E3B956F93FBFF0D41908483888F0F75D4714662A692F7A38DC6C41A13294F9370220471991BECB3CA4F43413CADC8FF738A8CC03568BFA832B4DCFE8C469080984E5"  # noqa: E501
+            elif self._firmware == Firmware.STAX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501041546304402206731FCD3E2432C5CA162381392FD17AD3A41EEF852E1D706F21A656AB165263602204B89FAE8DBAF191E2D79FB00EBA80D613CB7EDF0BE960CB6F6B29D96E1437F5F"  # noqa: E501
+            elif self._firmware == Firmware.FLEX:
+                cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010515473045022100B59EA8B958AA40578A6FBE9BBFB761020ACD5DBD8AA863C11DA17F42B2AFDE790220186316059EFA58811337D47C7F815F772EA42BBBCEA4AE123D1118C80588F5CB"  # noqa: E501
+            # pylint: enable=line-too-long
+
+            self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu))
+
         if sig is None:
             # Temporarily get a command with an empty signature to extract the payload and
             # compute the signature on it
diff --git a/client/src/ledger_app_clients/ethereum/command_builder.py b/client/src/ledger_app_clients/ethereum/command_builder.py
index bcd505cbe..ee59fb12e 100644
--- a/client/src/ledger_app_clients/ethereum/command_builder.py
+++ b/client/src/ledger_app_clients/ethereum/command_builder.py
@@ -23,7 +23,7 @@ class InsType(IntEnum):
     EIP712_SEND_FILTERING = 0x1e
     EIP712_SIGN = 0x0c
     GET_CHALLENGE = 0x20
-    PROVIDE_DOMAIN_NAME = 0x22
+    PROVIDE_TRUSTED_NAME = 0x22
     EXTERNAL_PLUGIN_SETUP = 0x12
 
 
@@ -41,7 +41,9 @@ class P2Type(IntEnum):
     LEGACY_IMPLEM = 0x00
     NEW_IMPLEM = 0x01
     FILTERING_ACTIVATE = 0x00
+    FILTERING_DISCARDED_PATH = 0x01
     FILTERING_MESSAGE_INFO = 0x0f
+    FILTERING_TRUSTED_NAME = 0xfb
     FILTERING_DATETIME = 0xfc
     FILTERING_TOKEN_ADDR_CHECK = 0xfd
     FILTERING_AMOUNT_FIELD = 0xfe
@@ -164,6 +166,15 @@ def _eip712_filtering_send_name(self, name: str, sig: bytes) -> bytes:
         data += sig
         return data
 
+    def eip712_filtering_discarded_path(self, path: str) -> bytes:
+        data = bytearray()
+        data.append(len(path))
+        data += path.encode()
+        return self._serialize(InsType.EIP712_SEND_FILTERING,
+                               P1Type.COMPLETE_SEND,
+                               P2Type.FILTERING_DISCARDED_PATH,
+                               data)
+
     def eip712_filtering_message_info(self, name: str, filters_count: int, sig: bytes) -> bytes:
         data = bytearray()
         data.append(len(name))
@@ -176,17 +187,17 @@ def eip712_filtering_message_info(self, name: str, filters_count: int, sig: byte
                                P2Type.FILTERING_MESSAGE_INFO,
                                data)
 
-    def eip712_filtering_amount_join_token(self, token_idx: int, sig: bytes) -> bytes:
+    def eip712_filtering_amount_join_token(self, token_idx: int, sig: bytes, discarded: bool) -> bytes:
         data = bytearray()
         data.append(token_idx)
         data.append(len(sig))
         data += sig
         return self._serialize(InsType.EIP712_SEND_FILTERING,
-                               P1Type.COMPLETE_SEND,
+                               int(discarded),
                                P2Type.FILTERING_TOKEN_ADDR_CHECK,
                                data)
 
-    def eip712_filtering_amount_join_value(self, token_idx: int, name: str, sig: bytes) -> bytes:
+    def eip712_filtering_amount_join_value(self, token_idx: int, name: str, sig: bytes, discarded: bool) -> bytes:
         data = bytearray()
         data.append(len(name))
         data += name.encode()
@@ -194,19 +205,41 @@ def eip712_filtering_amount_join_value(self, token_idx: int, name: str, sig: byt
         data.append(len(sig))
         data += sig
         return self._serialize(InsType.EIP712_SEND_FILTERING,
-                               P1Type.COMPLETE_SEND,
+                               int(discarded),
                                P2Type.FILTERING_AMOUNT_FIELD,
                                data)
 
-    def eip712_filtering_datetime(self, name: str, sig: bytes) -> bytes:
+    def eip712_filtering_datetime(self, name: str, sig: bytes, discarded: bool) -> bytes:
         return self._serialize(InsType.EIP712_SEND_FILTERING,
-                               P1Type.COMPLETE_SEND,
+                               int(discarded),
                                P2Type.FILTERING_DATETIME,
                                self._eip712_filtering_send_name(name, sig))
 
-    def eip712_filtering_raw(self, name: str, sig: bytes) -> bytes:
+    def eip712_filtering_trusted_name(self,
+                                      name: str,
+                                      name_types: list[int],
+                                      name_sources: list[int],
+                                      sig: bytes,
+                                      discarded: bool) -> bytes:
+        data = bytearray()
+        data.append(len(name))
+        data += name.encode()
+        data.append(len(name_types))
+        for t in name_types:
+            data.append(t)
+        data.append(len(name_sources))
+        for s in name_sources:
+            data.append(s)
+        data.append(len(sig))
+        data += sig
         return self._serialize(InsType.EIP712_SEND_FILTERING,
-                               P1Type.COMPLETE_SEND,
+                               int(discarded),
+                               P2Type.FILTERING_TRUSTED_NAME,
+                               data)
+
+    def eip712_filtering_raw(self, name: str, sig: bytes, discarded: bool) -> bytes:
+        return self._serialize(InsType.EIP712_SEND_FILTERING,
+                               int(discarded),
                                P2Type.FILTERING_RAW,
                                self._eip712_filtering_send_name(name, sig))
 
@@ -250,13 +283,13 @@ def sign(self, bip32_path: str, rlp_data: bytes, vrs: list) -> list[bytes]:
     def get_challenge(self) -> bytes:
         return self._serialize(InsType.GET_CHALLENGE, 0x00, 0x00)
 
-    def provide_domain_name(self, tlv_payload: bytes) -> list[bytes]:
+    def provide_trusted_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:
-            chunks.append(self._serialize(InsType.PROVIDE_DOMAIN_NAME,
+            chunks.append(self._serialize(InsType.PROVIDE_TRUSTED_NAME,
                                           p1,
                                           0x00,
                                           payload[:0xff]))
diff --git a/client/src/ledger_app_clients/ethereum/eip712/InputData.py b/client/src/ledger_app_clients/ethereum/eip712/InputData.py
index 4981abd4f..c83e37ef9 100644
--- a/client/src/ledger_app_clients/ethereum/eip712/InputData.py
+++ b/client/src/ledger_app_clients/ethereum/eip712/InputData.py
@@ -12,10 +12,13 @@
 
 from ragger.firmware import Firmware
 
+from client.client import PKIPubKeyUsage
+
 # global variables
 app_client: EthAppClient = None
 filtering_paths: dict = {}
-current_path: list[str] = list()
+filtering_tokens: list[dict] = []
+current_path: list[str] = []
 sig_ctx: dict[str, Any] = {}
 
 
@@ -192,32 +195,60 @@ def encode_bytes_dyn(value: str, typesize: int) -> bytes:
 encoding_functions[EIP712FieldType.DYN_BYTES] = encode_bytes_dyn
 
 
+def send_filtering_token(token_idx: int):
+    assert token_idx < len(filtering_tokens)
+    if len(filtering_tokens[token_idx]) > 0:
+        token = filtering_tokens[token_idx]
+        if not token["sent"]:
+            app_client.provide_token_metadata(token["ticker"],
+                                              bytes.fromhex(token["addr"][2:]),
+                                              token["decimals"],
+                                              token["chain_id"])
+            token["sent"] = True
+
+
+def send_filter(path: str, discarded: bool):
+    assert path in filtering_paths.keys()
+
+    if filtering_paths[path]["type"].startswith("amount_join_"):
+        if "token" in filtering_paths[path].keys():
+            token_idx = filtering_paths[path]["token"]
+            send_filtering_token(token_idx)
+        else:
+            # Permit (ERC-2612)
+            send_filtering_token(0)
+            token_idx = 0xff
+        if filtering_paths[path]["type"].endswith("_token"):
+            send_filtering_amount_join_token(path, token_idx, discarded)
+        elif filtering_paths[path]["type"].endswith("_value"):
+            send_filtering_amount_join_value(path,
+                                             token_idx,
+                                             filtering_paths[path]["name"],
+                                             discarded)
+    elif filtering_paths[path]["type"] == "datetime":
+        send_filtering_datetime(path, filtering_paths[path]["name"], discarded)
+    elif filtering_paths[path]["type"] == "trusted_name":
+        send_filtering_trusted_name(path,
+                                    filtering_paths[path]["name"],
+                                    filtering_paths[path]["tn_type"],
+                                    filtering_paths[path]["tn_source"],
+                                    discarded)
+    elif filtering_paths[path]["type"] == "raw":
+        send_filtering_raw(path, filtering_paths[path]["name"], discarded)
+    else:
+        assert False
+
+
 def send_struct_impl_field(value, field):
-    # Something wrong happened if this triggers
-    if isinstance(value, list) or (field["enum"] == EIP712FieldType.CUSTOM):
-        breakpoint()
+    assert not isinstance(value, list)
+    assert field["enum"] != EIP712FieldType.CUSTOM
 
     data = encoding_functions[field["enum"]](value, field["typesize"])
 
     if filtering_paths:
         path = ".".join(current_path)
         if path in filtering_paths.keys():
-            if filtering_paths[path]["type"] == "amount_join_token":
-                send_filtering_amount_join_token(filtering_paths[path]["token"])
-            elif filtering_paths[path]["type"] == "amount_join_value":
-                if "token" in filtering_paths[path].keys():
-                    token = filtering_paths[path]["token"]
-                else:
-                    # Permit (ERC-2612)
-                    token = 0xff
-                send_filtering_amount_join_value(token,
-                                                 filtering_paths[path]["name"])
-            elif filtering_paths[path]["type"] == "datetime":
-                send_filtering_datetime(filtering_paths[path]["name"])
-            elif filtering_paths[path]["type"] == "raw":
-                send_filtering_raw(filtering_paths[path]["name"])
-            else:
-                assert False
+            send_filter(path, False)
 
     with app_client.eip712_send_struct_impl_struct_field(data):
         enable_autonext()
@@ -232,6 +263,12 @@ def evaluate_field(structs, data, field, lvls_left, new_level=True):
     if len(array_lvls) > 0 and lvls_left > 0:
         with app_client.eip712_send_struct_impl_array(len(data)):
             pass
+        if len(data) == 0:
+            for path in filtering_paths.keys():
+                dpath = ".".join(current_path) + ".[]"
+                if path.startswith(dpath):
+                    app_client.eip712_filtering_discarded_path(path)
+                    send_filter(path, True)
         idx = 0
         for subdata in data:
             current_path.append("[]")
@@ -293,73 +330,87 @@ def send_filtering_message_info(display_name: str, filters_count: int):
     disable_autonext()
 
 
-def send_filtering_amount_join_token(token_idx: int):
+def send_filtering_amount_join_token(path: str, token_idx: int, discarded: bool):
     global sig_ctx
 
-    path_str = ".".join(current_path)
-
     to_sign = start_signature_payload(sig_ctx, 11)
-    to_sign += path_str.encode()
+    to_sign += path.encode()
     to_sign.append(token_idx)
     sig = keychain.sign_data(keychain.Key.CAL, to_sign)
-    with app_client.eip712_filtering_amount_join_token(token_idx, sig):
+    with app_client.eip712_filtering_amount_join_token(token_idx, sig, discarded):
         pass
 
 
-def send_filtering_amount_join_value(token_idx: int, display_name: str):
+def send_filtering_amount_join_value(path: str, token_idx: int, display_name: str, discarded: bool):
     global sig_ctx
 
-    path_str = ".".join(current_path)
-
     to_sign = start_signature_payload(sig_ctx, 22)
-    to_sign += path_str.encode()
+    to_sign += path.encode()
     to_sign += display_name.encode()
     to_sign.append(token_idx)
     sig = keychain.sign_data(keychain.Key.CAL, to_sign)
-    with app_client.eip712_filtering_amount_join_value(token_idx, display_name, sig):
+    with app_client.eip712_filtering_amount_join_value(token_idx, display_name, sig, discarded):
         pass
 
 
-def send_filtering_datetime(display_name: str):
+def send_filtering_datetime(path: str, display_name: str, discarded: bool):
     global sig_ctx
 
-    path_str = ".".join(current_path)
-
     to_sign = start_signature_payload(sig_ctx, 33)
-    to_sign += path_str.encode()
+    to_sign += path.encode()
     to_sign += display_name.encode()
     sig = keychain.sign_data(keychain.Key.CAL, to_sign)
-    with app_client.eip712_filtering_datetime(display_name, sig):
+    with app_client.eip712_filtering_datetime(display_name, sig, discarded):
         pass
 
 
-# ledgerjs doesn't actually sign anything, and instead uses already pre-computed signatures
-def send_filtering_raw(display_name):
+def send_filtering_trusted_name(path: str,
+                                display_name: str,
+                                name_type: list[int],
+                                name_source: list[int],
+                                discarded: bool):
     global sig_ctx
 
-    path_str = ".".join(current_path)
+    to_sign = start_signature_payload(sig_ctx, 44)
+    to_sign += path.encode()
+    to_sign += display_name.encode()
+    for t in name_type:
+        to_sign.append(t)
+    for s in name_source:
+        to_sign.append(s)
+    sig = keychain.sign_data(keychain.Key.CAL, to_sign)
+    with app_client.eip712_filtering_trusted_name(display_name, name_type, name_source, sig, discarded):
+        pass
+
+
+# ledgerjs doesn't actually sign anything, and instead uses already pre-computed signatures
+def send_filtering_raw(path: str, display_name: str, discarded: bool):
+    global sig_ctx
 
     to_sign = start_signature_payload(sig_ctx, 72)
-    to_sign += path_str.encode()
+    to_sign += path.encode()
     to_sign += display_name.encode()
     sig = keychain.sign_data(keychain.Key.CAL, to_sign)
-    with app_client.eip712_filtering_raw(display_name, sig):
+    with app_client.eip712_filtering_raw(display_name, sig, discarded):
         pass
 
 
 def prepare_filtering(filtr_data, message):
     global filtering_paths
+    global filtering_tokens
 
     if "fields" in filtr_data:
         filtering_paths = filtr_data["fields"]
     else:
         filtering_paths = {}
+
     if "tokens" in filtr_data:
-        for token in filtr_data["tokens"]:
-            app_client.provide_token_metadata(token["ticker"],
-                                              bytes.fromhex(token["addr"][2:]),
-                                              token["decimals"],
-                                              token["chain_id"])
+        filtering_tokens = filtr_data["tokens"]
+        for token in filtering_tokens:
+            if len(token) > 0:
+                token["sent"] = False
+    else:
+        filtering_tokens = []
 
 
 def handle_optional_domain_values(domain):
@@ -450,6 +501,22 @@ def process_data(aclient: EthAppClient,
             pass
         prepare_filtering(filters, message)
 
+    if aclient._pki_client is None:
+        print(f"Ledger-PKI Not supported on '{aclient._firmware.name}'")
+    else:
+        # pylint: disable=line-too-long
+        if aclient._firmware == Firmware.NANOSP:
+            cert_apdu = "0101010201021004010200001104000000021201001302000214010116040000000020104549503731325f46696c746572696e67300200053101083201213321024cca8fad496aa5040a00a7eb2f5cc3b85376d88ba147a7d7054a99c64056188734010135010315473045022100ef197e5b1cabb3de5dfc62f965db8536b0463d272c6fea38ebc73605715b1df9022017bef619d52a9728b37a9b5a33f0143bcdcc714694eed07c326796ffbb7c2958"  # noqa: E501
+        elif aclient._firmware == Firmware.NANOX:
+            cert_apdu = "0101010201021104000000021201001302000214010116040000000020104549503731325F46696C746572696E67300200053101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010215473045022100E07E129B0DC2A571D5205C3DB43BF4BB3463A2E9D2A4EEDBEC8FD3518CC5A95902205F80306EEF785C4D45BDCA1F25394A1341571BD1921C2740392DD22EB1ACDD8B"  # noqa: E501
+        elif aclient._firmware == Firmware.STAX:
+            cert_apdu = "0101010201021104000000021201001302000214010116040000000020104549503731325F46696C746572696E67300200053101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501041546304402204EA7B30F0EEFEF25FAB3ADDA6609E25296C41DD1C5969A92FAE6B600AAC2902E02206212054E123F5F965F787AE7EE565E243F21B11725626D3FF058522D6BDCD995"  # noqa: E501
+        elif aclient._firmware == Firmware.FLEX:
+            cert_apdu = "0101010201021104000000021201001302000214010116040000000020104549503731325F46696C746572696E67300200053101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501051546304402205FB5E970065A95C57F00FFA3964946251815527613724ED6745C37E303934BE702203CC9F4124B42806F0A7CA765CFAB5AADEB280C35AB8F809FC49ADC97D9B9CE15"  # noqa: E501
+        # pylint: enable=line-too-long
+
+        aclient._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu))
+
     # send domain implementation
     with app_client.eip712_send_struct_impl_root_struct(domain_typename):
         enable_autonext()
diff --git a/client/src/ledger_app_clients/ethereum/keychain.py b/client/src/ledger_app_clients/ethereum/keychain.py
index 0fc6712b1..4eb638573 100644
--- a/client/src/ledger_app_clients/ethereum/keychain.py
+++ b/client/src/ledger_app_clients/ethereum/keychain.py
@@ -9,7 +9,7 @@
 # Example: for an entry in the Enum named DEV, its PEM file must be at keychain/dev.pem
 class Key(Enum):
     CAL = auto()
-    DOMAIN_NAME = auto()
+    TRUSTED_NAME = auto()
     SET_PLUGIN = auto()
     NFT = auto()
 
diff --git a/client/src/ledger_app_clients/ethereum/keychain/domain_name.pem b/client/src/ledger_app_clients/ethereum/keychain/trusted_name.pem
similarity index 100%
rename from client/src/ledger_app_clients/ethereum/keychain/domain_name.pem
rename to client/src/ledger_app_clients/ethereum/keychain/trusted_name.pem
diff --git a/client/src/ledger_app_clients/ethereum/settings.py b/client/src/ledger_app_clients/ethereum/settings.py
index dc2b40cec..25718b6dc 100644
--- a/client/src/ledger_app_clients/ethereum/settings.py
+++ b/client/src/ledger_app_clients/ethereum/settings.py
@@ -28,32 +28,27 @@ def get_device_settings(firmware: Firmware) -> list[SettingID]:
     ]
 
 
-def get_setting_per_page(firmware: Firmware) -> int:
-    if firmware == Firmware.STAX:
-        return 3
-    return 2
-
-
-def get_setting_position(firmware: Firmware, setting: Union[NavInsID, SettingID]) -> tuple[int, int]:
-    settings_per_page = get_setting_per_page(firmware)
+def get_setting_position(firmware: Firmware, setting_idx: int, per_page: int) -> tuple[int, int]:
     if firmware == Firmware.STAX:
         screen_height = 672  # px
+        screen_width = 400  # px
         header_height = 88  # px
         footer_height = 92  # px
-        option_offset = 350  # px
     else:
         screen_height = 600  # px
-        header_height = 92  # px
-        footer_height = 97  # px
-        option_offset = 420  # px
+        screen_width = 480  # px
+        header_height = 96  # px
+        footer_height = 96  # px
+
+    index_in_page = setting_idx % per_page
     usable_height = screen_height - (header_height + footer_height)
-    setting_height = usable_height // settings_per_page
-    index_in_page = get_device_settings(firmware).index(SettingID(setting)) % settings_per_page
-    return option_offset, header_height + (setting_height * index_in_page) + (setting_height // 2)
+    setting_height = usable_height // per_page
+    offset = (setting_height * index_in_page) + (setting_height // 2)
+    return screen_width // 2, header_height + offset
 
 
 def settings_toggle(firmware: Firmware, nav: Navigator, to_toggle: list[SettingID]):
-    moves: list[Union[NavIns, NavInsID]] = list()
+    moves: list[Union[NavIns, NavInsID]] = []
     settings = get_device_settings(firmware)
     # Assume the app is on the home page
     if firmware.is_nano:
@@ -66,12 +61,12 @@ def settings_toggle(firmware: Firmware, nav: Navigator, to_toggle: list[SettingI
         moves += [NavInsID.BOTH_CLICK]  # Back
     else:
         moves += [NavInsID.USE_CASE_HOME_SETTINGS]
-        settings_per_page = get_setting_per_page(firmware)
+        settings_per_page = 3 if firmware == Firmware.STAX else 2
         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(firmware, setting))]
+                moves += [NavIns(NavInsID.TOUCH, get_setting_position(firmware, setting_idx, settings_per_page))]
         moves += [NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT]
     nav.navigate(moves, screen_change_before_first_instruction=False)
diff --git a/doc/ethapp.adoc b/doc/ethapp.adoc
index 35a0d98e7..90bdef47d 100644
--- a/doc/ethapp.adoc
+++ b/doc/ethapp.adoc
@@ -39,12 +39,16 @@ Application version 1.9.19 - 2022-05-17
   - Update to SIGN ETH EIP712
 
 ### 1.10.2
-  - Add domain names support
+  - Add trusted names support
 
 ### 1.11.0
-  - Add EIP-712 amount & date/time filtering
+  - Add EIP-712 amount-join & date/time filtering
   - PROVIDE ERC 20 TOKEN INFORMATION & PROVIDE NFT INFORMATION now send back the index where the asset has been stored
 
+### 1.12.0
+  - Add EIP-712 discarded filter path support
+  - Add EIP-712 trusted name filtering
+
 ## About
 
 This application describes the APDU messages interface to communicate with the Ethereum application.
@@ -828,6 +832,12 @@ Field substitution will be ignored if the full filtering is not activated.
 
 This command should come before the domain & message implementations. If activated, fields will be by default hidden unless they receive a field name substitution.
 
+##### Discarded filter path
+
+This command gives the app the absolute path of the upcoming filter which will be discarded (because it targets a field within an empty array).
+
+The next filter should be marked as discarded (with P1) to be able to use this given filter path.
+
 ##### Message info
 
 This command should come right after the implementation of the domain has been sent with *SEND STRUCT IMPLEMENTATION*, just before sending the message implementation.
@@ -849,6 +859,7 @@ The signature is computed on :
 ##### Amount-join value
 
 This command should come before the corresponding *SEND STRUCT IMPLEMENTATION* and are only usable for message fields (and not domain ones).
+The first byte is used so that a signature of one type cannot be valid as another type.
 
 A token index of 0xFF indicates the token address is in the _verifyingContract_ field of the EIP712Domain so the app won't receive an amount-join token filtering APDU. This enables support for Permit (ERC-2612) messages.
 
@@ -859,11 +870,21 @@ The signature is computed on :
 ##### Date / Time
 
 This command should come before the corresponding *SEND STRUCT IMPLEMENTATION* and are only usable for message fields (and not domain ones).
+The first byte is used so that a signature of one type cannot be valid as another type.
 
 The signature is computed on :
 
 33 || chain ID (BE) || contract address || schema hash || field path || display name
 
+##### Trusted name
+
+This command should come right after the implementation of the domain has been sent with *SEND STRUCT IMPLEMENTATION*, just before sending the message implementation.
+The first byte is used so that a signature of one type cannot be valid as another type.
+
+The signature is computed on :
+
+44 || chain ID (BE) || contract address || schema hash || field path || display name || name types || name sources
+
 ##### Show raw field
 
 This command should come before the corresponding *SEND STRUCT IMPLEMENTATION* and are only usable for message fields (and not domain ones).
@@ -880,11 +901,16 @@ _Command_
 [width="80%"]
 |=========================================================================
 | *CLA* | *INS*  | *P1*               | *P2*       | *LC*     | *Le*
-|   E0  |   1E   | 00
-                                      | 00 : activation
+|   E0  |   1E   | 00 : standard
+
+                   01 : discarded     | 00 : activation
+
+                                        01 : discarded filter path
 
                                         0F : message info
 
+                                        FB : trusted name
+
                                         FC : date/time
 
                                         FD : amount-join token
@@ -901,6 +927,15 @@ _Input data_
 
 None
 
+##### If P2 == discarded filter path
+
+[width="80%"]
+|==========================================
+| *Description*         | *Length (byte)*
+| Path length           | 1
+| Path                  | variable
+|==========================================
+
 ##### If P2 == message info
 
 [width="80%"]
@@ -913,6 +948,21 @@ None
 | Signature             | variable
 |==========================================
 
+##### If P2 == trusted name
+
+[width="80%"]
+|==========================================
+| *Description*         | *Length (byte)*
+| Display name length   | 1
+| Display name          | variable
+| Name types count      | 1
+| Name types            | variable
+| Name sources count    | 1
+| Name sources          | variable
+| Signature length      | 1
+| Signature             | variable
+|==========================================
+
 ##### If P2 == date / time
 
 [width="80%"]
@@ -992,12 +1042,13 @@ _Output data_
 |===========================================
 
 
-### PROVIDE DOMAIN NAME
+### PROVIDE TRUSTED NAME
 
 #### Description
 
-This command provides a domain name (like ENS) to be displayed during transactions in place of the address it is associated to.
-It shall be run just before a transaction involving the associated address that would be displayed on the device.
+This command provides a trusted name (like an ENS domain) to be displayed during transactions in place of the
+address it is associated to. It shall be run just before a transaction/message involving the associated
+address that would be displayed on the device.
 
 The signature is computed on the TLV payload (minus the signature obviously).
 
@@ -1122,14 +1173,22 @@ The following standard Status Words are returned for all APDUs - some specific S
 [width="80%"]
 |===============================================================================================
 | *SW*     | *Description*
+|   6001   | Mode check fail
 |   6501   | TransactionType not supported
 |   6502   | Output buffer too small for chainId conversion
-|   6503   | Plugin error
-|   6504   | Failed to convert from int256
-|   6700   | Incorrect length
+|   68xx   | Internal error (Please report)
 |   6982   | Security status not satisfied (Canceled by user)
+|   6983   | Wrong Data length
+|   6984   | Plugin not installed
+|   6985   | Condition not satisfied
+|   6A00   | Error without info
 |   6A80   | Invalid data
+|   6A84   | Insufficient memory
+|   6A88   | Data not found
 |   6B00   | Incorrect parameter P1 or P2
+|   6D00   | Incorrect parameter INS
+|   6E00   | Incorrect parameter CLA
 |   6Fxx   | Technical problem (Internal error, please report)
 |   9000   | Normal ending of the command
+|   911C   | Command code not supported (i.e. Ledger-PKI not yet available)
 |===============================================================================================
diff --git a/ethereum-plugin-sdk b/ethereum-plugin-sdk
index 0afd2a969..26662539b 160000
--- a/ethereum-plugin-sdk
+++ b/ethereum-plugin-sdk
@@ -1,1 +1,1 @@
-Subproject commit 0afd2a969eb23e8a508560e0e308dc51fb9219e0
+Subproject commit 26662539b1cd62ae7ef4826d66690dad80cb9bab
diff --git a/glyphs/chain_1284_64px.gif b/glyphs/chain_1284_64px.gif
index e8485ee55..5856cfa6a 100644
Binary files a/glyphs/chain_1284_64px.gif and b/glyphs/chain_1284_64px.gif differ
diff --git a/glyphs/chain_1285_64px.gif b/glyphs/chain_1285_64px.gif
index 180985709..89d465a7a 100644
Binary files a/glyphs/chain_1285_64px.gif and b/glyphs/chain_1285_64px.gif differ
diff --git a/glyphs/chain_943_64px.gif b/glyphs/chain_943_64px.gif
new file mode 120000
index 000000000..2192306a5
--- /dev/null
+++ b/glyphs/chain_943_64px.gif
@@ -0,0 +1,1 @@
+chain_369_64px.gif
\ No newline at end of file
diff --git a/icons/flex_app_chain_1030.gif b/icons/flex_app_chain_1030.gif
deleted file mode 100644
index 6a4039d3f..000000000
Binary files a/icons/flex_app_chain_1030.gif and /dev/null differ
diff --git a/icons/flex_app_chain_1284.gif b/icons/flex_app_chain_1284.gif
index dd919fc6f..0dbbeccb0 100644
Binary files a/icons/flex_app_chain_1284.gif and b/icons/flex_app_chain_1284.gif differ
diff --git a/icons/flex_app_chain_1285.gif b/icons/flex_app_chain_1285.gif
index f3ef9f46d..50b15c24a 100644
Binary files a/icons/flex_app_chain_1285.gif and b/icons/flex_app_chain_1285.gif differ
diff --git a/icons/flex_app_chain_137.gif b/icons/flex_app_chain_137.gif
deleted file mode 100644
index b49f73b46..000000000
Binary files a/icons/flex_app_chain_137.gif and /dev/null differ
diff --git a/icons/flex_app_chain_1818.gif b/icons/flex_app_chain_1818.gif
deleted file mode 100644
index 6af034e82..000000000
Binary files a/icons/flex_app_chain_1818.gif and /dev/null differ
diff --git a/icons/flex_app_chain_199.gif b/icons/flex_app_chain_199.gif
deleted file mode 100644
index d7d927686..000000000
Binary files a/icons/flex_app_chain_199.gif and /dev/null differ
diff --git a/icons/flex_app_chain_24.gif b/icons/flex_app_chain_24.gif
deleted file mode 100644
index a4f59ce60..000000000
Binary files a/icons/flex_app_chain_24.gif and /dev/null differ
diff --git a/icons/flex_app_chain_51.gif b/icons/flex_app_chain_51.gif
deleted file mode 100644
index e2a694f7d..000000000
Binary files a/icons/flex_app_chain_51.gif and /dev/null differ
diff --git a/icons/flex_app_chain_56.gif b/icons/flex_app_chain_56.gif
deleted file mode 100644
index 1dd9c54e5..000000000
Binary files a/icons/flex_app_chain_56.gif and /dev/null differ
diff --git a/icons/flex_app_chain_62621.gif b/icons/flex_app_chain_62621.gif
deleted file mode 100644
index c8dc4076e..000000000
Binary files a/icons/flex_app_chain_62621.gif and /dev/null differ
diff --git a/icons/flex_app_chain_66.gif b/icons/flex_app_chain_66.gif
deleted file mode 100644
index f1db75aa5..000000000
Binary files a/icons/flex_app_chain_66.gif and /dev/null differ
diff --git a/icons/flex_app_chain_7341.gif b/icons/flex_app_chain_7341.gif
deleted file mode 100644
index bf6bd6188..000000000
Binary files a/icons/flex_app_chain_7341.gif and /dev/null differ
diff --git a/icons/flex_app_chain_82.gif b/icons/flex_app_chain_82.gif
deleted file mode 100644
index d7cd90bcd..000000000
Binary files a/icons/flex_app_chain_82.gif and /dev/null differ
diff --git a/icons/flex_app_chain_99.gif b/icons/flex_app_chain_99.gif
deleted file mode 100644
index cd615c569..000000000
Binary files a/icons/flex_app_chain_99.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_1030.gif b/icons/nanos_app_chain_1030.gif
deleted file mode 100644
index 02e793131..000000000
Binary files a/icons/nanos_app_chain_1030.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_1284.gif b/icons/nanos_app_chain_1284.gif
index 2a254b24b..953cf6d7c 100644
Binary files a/icons/nanos_app_chain_1284.gif and b/icons/nanos_app_chain_1284.gif differ
diff --git a/icons/nanos_app_chain_1285.gif b/icons/nanos_app_chain_1285.gif
index 5cc7ce20a..0f7d89aa4 100644
Binary files a/icons/nanos_app_chain_1285.gif and b/icons/nanos_app_chain_1285.gif differ
diff --git a/icons/nanos_app_chain_137.gif b/icons/nanos_app_chain_137.gif
deleted file mode 100644
index bf660ac0b..000000000
Binary files a/icons/nanos_app_chain_137.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_1818.gif b/icons/nanos_app_chain_1818.gif
deleted file mode 100644
index 1e1d755ab..000000000
Binary files a/icons/nanos_app_chain_1818.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_199.gif b/icons/nanos_app_chain_199.gif
deleted file mode 100644
index 475509535..000000000
Binary files a/icons/nanos_app_chain_199.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_24.gif b/icons/nanos_app_chain_24.gif
deleted file mode 100644
index ed096104e..000000000
Binary files a/icons/nanos_app_chain_24.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_51.gif b/icons/nanos_app_chain_51.gif
deleted file mode 100644
index f9d105ac0..000000000
Binary files a/icons/nanos_app_chain_51.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_56.gif b/icons/nanos_app_chain_56.gif
deleted file mode 100644
index 290d658dc..000000000
Binary files a/icons/nanos_app_chain_56.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_62621.gif b/icons/nanos_app_chain_62621.gif
deleted file mode 100644
index f8853eb2b..000000000
Binary files a/icons/nanos_app_chain_62621.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_66.gif b/icons/nanos_app_chain_66.gif
deleted file mode 100644
index ef6b29c4d..000000000
Binary files a/icons/nanos_app_chain_66.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_7341.gif b/icons/nanos_app_chain_7341.gif
deleted file mode 100644
index b96efa1d9..000000000
Binary files a/icons/nanos_app_chain_7341.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_82.gif b/icons/nanos_app_chain_82.gif
deleted file mode 100644
index 7da65b4f9..000000000
Binary files a/icons/nanos_app_chain_82.gif and /dev/null differ
diff --git a/icons/nanos_app_chain_99.gif b/icons/nanos_app_chain_99.gif
deleted file mode 100644
index e466b2caf..000000000
Binary files a/icons/nanos_app_chain_99.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_1030.gif b/icons/nanox_app_chain_1030.gif
deleted file mode 100644
index 8b74623ee..000000000
Binary files a/icons/nanox_app_chain_1030.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_1284.gif b/icons/nanox_app_chain_1284.gif
index 0da2ed11b..6fd9373e3 100644
Binary files a/icons/nanox_app_chain_1284.gif and b/icons/nanox_app_chain_1284.gif differ
diff --git a/icons/nanox_app_chain_1285.gif b/icons/nanox_app_chain_1285.gif
index 363834f3d..a94435547 100644
Binary files a/icons/nanox_app_chain_1285.gif and b/icons/nanox_app_chain_1285.gif differ
diff --git a/icons/nanox_app_chain_137.gif b/icons/nanox_app_chain_137.gif
deleted file mode 100644
index 3769ce7d0..000000000
Binary files a/icons/nanox_app_chain_137.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_1818.gif b/icons/nanox_app_chain_1818.gif
deleted file mode 100644
index 912c760e5..000000000
Binary files a/icons/nanox_app_chain_1818.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_199.gif b/icons/nanox_app_chain_199.gif
deleted file mode 100644
index 4b0b8d4d8..000000000
Binary files a/icons/nanox_app_chain_199.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_24.gif b/icons/nanox_app_chain_24.gif
deleted file mode 100644
index 4cd245ff0..000000000
Binary files a/icons/nanox_app_chain_24.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_51.gif b/icons/nanox_app_chain_51.gif
deleted file mode 100644
index 387354d90..000000000
Binary files a/icons/nanox_app_chain_51.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_56.gif b/icons/nanox_app_chain_56.gif
deleted file mode 100644
index 36b0a8264..000000000
Binary files a/icons/nanox_app_chain_56.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_62621.gif b/icons/nanox_app_chain_62621.gif
deleted file mode 100644
index 77bf0f0d3..000000000
Binary files a/icons/nanox_app_chain_62621.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_66.gif b/icons/nanox_app_chain_66.gif
deleted file mode 100644
index 5f729da9b..000000000
Binary files a/icons/nanox_app_chain_66.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_7341.gif b/icons/nanox_app_chain_7341.gif
deleted file mode 100644
index bab985086..000000000
Binary files a/icons/nanox_app_chain_7341.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_82.gif b/icons/nanox_app_chain_82.gif
deleted file mode 100644
index d67c25f3a..000000000
Binary files a/icons/nanox_app_chain_82.gif and /dev/null differ
diff --git a/icons/nanox_app_chain_99.gif b/icons/nanox_app_chain_99.gif
deleted file mode 100644
index 951bb4960..000000000
Binary files a/icons/nanox_app_chain_99.gif and /dev/null differ
diff --git a/icons/stax_app_chain_1030.gif b/icons/stax_app_chain_1030.gif
deleted file mode 100644
index e39f4425b..000000000
Binary files a/icons/stax_app_chain_1030.gif and /dev/null differ
diff --git a/icons/stax_app_chain_1284.gif b/icons/stax_app_chain_1284.gif
index c8d2c9b0b..24f8c9bb7 100644
Binary files a/icons/stax_app_chain_1284.gif and b/icons/stax_app_chain_1284.gif differ
diff --git a/icons/stax_app_chain_1285.gif b/icons/stax_app_chain_1285.gif
index 69466a7a5..0ad7f34b0 100644
Binary files a/icons/stax_app_chain_1285.gif and b/icons/stax_app_chain_1285.gif differ
diff --git a/icons/stax_app_chain_137.gif b/icons/stax_app_chain_137.gif
deleted file mode 100644
index eba2eaad3..000000000
Binary files a/icons/stax_app_chain_137.gif and /dev/null differ
diff --git a/icons/stax_app_chain_1818.gif b/icons/stax_app_chain_1818.gif
deleted file mode 100644
index 1a5b3c8e6..000000000
Binary files a/icons/stax_app_chain_1818.gif and /dev/null differ
diff --git a/icons/stax_app_chain_199.gif b/icons/stax_app_chain_199.gif
deleted file mode 100644
index cc8a3f986..000000000
Binary files a/icons/stax_app_chain_199.gif and /dev/null differ
diff --git a/icons/stax_app_chain_24.gif b/icons/stax_app_chain_24.gif
deleted file mode 100644
index 0c092ffa2..000000000
Binary files a/icons/stax_app_chain_24.gif and /dev/null differ
diff --git a/icons/stax_app_chain_51.gif b/icons/stax_app_chain_51.gif
deleted file mode 100644
index 381f07069..000000000
Binary files a/icons/stax_app_chain_51.gif and /dev/null differ
diff --git a/icons/stax_app_chain_56.gif b/icons/stax_app_chain_56.gif
deleted file mode 100644
index 311d31a04..000000000
Binary files a/icons/stax_app_chain_56.gif and /dev/null differ
diff --git a/icons/stax_app_chain_62621.gif b/icons/stax_app_chain_62621.gif
deleted file mode 100644
index ad33059e7..000000000
Binary files a/icons/stax_app_chain_62621.gif and /dev/null differ
diff --git a/icons/stax_app_chain_66.gif b/icons/stax_app_chain_66.gif
deleted file mode 100644
index 38cfa3cc3..000000000
Binary files a/icons/stax_app_chain_66.gif and /dev/null differ
diff --git a/icons/stax_app_chain_7341.gif b/icons/stax_app_chain_7341.gif
deleted file mode 100644
index 0741eddac..000000000
Binary files a/icons/stax_app_chain_7341.gif and /dev/null differ
diff --git a/icons/stax_app_chain_82.gif b/icons/stax_app_chain_82.gif
deleted file mode 100644
index d07813d1a..000000000
Binary files a/icons/stax_app_chain_82.gif and /dev/null differ
diff --git a/icons/stax_app_chain_99.gif b/icons/stax_app_chain_99.gif
deleted file mode 100644
index afa1186ba..000000000
Binary files a/icons/stax_app_chain_99.gif and /dev/null differ
diff --git a/ledger_app.toml b/ledger_app.toml
index a640f652a..fc54c10e9 100644
--- a/ledger_app.toml
+++ b/ledger_app.toml
@@ -3,9 +3,9 @@ build_directory = "./"
 sdk = "C"
 devices = ["nanos", "nanox", "nanos+", "stax", "flex"]
 
-[use_cases] # Coherent build options that make sense for your application
-test_keys = "CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
-dbg_test_keys = "DEBUG=1 CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
+[use_cases]
+use_test_keys = "CAL_TEST_KEY=1 TRUSTED_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
+dbg_use_test_keys = "DEBUG=1 CAL_TEST_KEY=1 TRUSTED_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
 cal_bypass = "BYPASS_SIGNATURES=1"
 dbg_cal_bypass = "DEBUG=1 BYPASS_SIGNATURES=1"
 
diff --git a/makefile_conf/chain/apothemnetwork.mk b/makefile_conf/chain/apothemnetwork.mk
deleted file mode 100644
index 34464823d..000000000
--- a/makefile_conf/chain/apothemnetwork.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/550'"
-TICKER = "TXDC"
-CHAIN_ID = 51
-APPNAME = "ApothemNetwork"
diff --git a/makefile_conf/chain/astar.mk b/makefile_conf/chain/astar.mk
index e1523260c..cfafbebf2 100644
--- a/makefile_conf/chain/astar.mk
+++ b/makefile_conf/chain/astar.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/810'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/810'"
 TICKER = "ASTR"
 CHAIN_ID = 592
 APPNAME = "Astar Polkadot EVM"
diff --git a/makefile_conf/chain/bsc.mk b/makefile_conf/chain/bsc.mk
deleted file mode 100644
index 3a478411b..000000000
--- a/makefile_conf/chain/bsc.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "BNB"
-CHAIN_ID = 56
-APPNAME = "Binance Smart Chain"
diff --git a/makefile_conf/chain/bttc.mk b/makefile_conf/chain/bttc.mk
deleted file mode 100644
index fdb1781fb..000000000
--- a/makefile_conf/chain/bttc.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "BTT"
-CHAIN_ID = 199
-APPNAME = "BTTC"
diff --git a/makefile_conf/chain/conflux_espace.mk b/makefile_conf/chain/conflux_espace.mk
deleted file mode 100644
index 2dd6a4b7f..000000000
--- a/makefile_conf/chain/conflux_espace.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "CFX"
-CHAIN_ID = 1030
-APPNAME = "Conflux eSpace"
diff --git a/makefile_conf/chain/cube.mk b/makefile_conf/chain/cube.mk
deleted file mode 100644
index 72b90bd38..000000000
--- a/makefile_conf/chain/cube.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "CUBE"
-CHAIN_ID = 1818
-APPNAME = "Cube"
diff --git a/makefile_conf/chain/energywebchain.mk b/makefile_conf/chain/energywebchain.mk
index 6dbf94fcc..c34c8134c 100644
--- a/makefile_conf/chain/energywebchain.mk
+++ b/makefile_conf/chain/energywebchain.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/246'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/246'"
 TICKER = "EWT"
 CHAIN_ID = 246
 APPNAME = "EnergyWebChain"
diff --git a/makefile_conf/chain/ethereum_classic.mk b/makefile_conf/chain/ethereum_classic.mk
index 1aea2af95..8c49bc70f 100644
--- a/makefile_conf/chain/ethereum_classic.mk
+++ b/makefile_conf/chain/ethereum_classic.mk
@@ -1,5 +1,5 @@
 # Also allows ETC to access the ETH derivation path to recover forked assets
-PATH_APP_LOAD_PARAMS += "44'/61'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/61'"
 TICKER = "ETC"
 CHAIN_ID = 61
 APPNAME = "Ethereum Classic"
diff --git a/makefile_conf/chain/kardiachain.mk b/makefile_conf/chain/kardiachain.mk
deleted file mode 100644
index 5d73e4500..000000000
--- a/makefile_conf/chain/kardiachain.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "KAI"
-CHAIN_ID = 24
-APPNAME = "KardiaChain"
diff --git a/makefile_conf/chain/meter.mk b/makefile_conf/chain/meter.mk
deleted file mode 100644
index 2089edcf5..000000000
--- a/makefile_conf/chain/meter.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "MTR"
-CHAIN_ID = 82
-APPNAME = "Meter"
diff --git a/makefile_conf/chain/moonbeam.mk b/makefile_conf/chain/moonbeam.mk
index edf4c3f50..4420f3f54 100644
--- a/makefile_conf/chain/moonbeam.mk
+++ b/makefile_conf/chain/moonbeam.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/60'" "44'/1284'"
+PATH_APP_LOAD_PARAMS += "44'/1284'"
 TICKER = "GLMR"
 CHAIN_ID = 1284
 APPNAME = "Moonbeam"
diff --git a/makefile_conf/chain/moonriver.mk b/makefile_conf/chain/moonriver.mk
index a777fe02e..d012dab7b 100644
--- a/makefile_conf/chain/moonriver.mk
+++ b/makefile_conf/chain/moonriver.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/60'" "44'/1285'"
+PATH_APP_LOAD_PARAMS += "44'/1285'"
 TICKER = "MOVR"
 CHAIN_ID = 1285
 APPNAME = "Moonriver"
diff --git a/makefile_conf/chain/multivac.mk b/makefile_conf/chain/multivac.mk
deleted file mode 100644
index 1fe26f946..000000000
--- a/makefile_conf/chain/multivac.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "MTV"
-CHAIN_ID = 62621
-APPNAME = "MultiVAC"
diff --git a/makefile_conf/chain/oasys.mk b/makefile_conf/chain/oasys.mk
index b75afc985..2342767c8 100644
--- a/makefile_conf/chain/oasys.mk
+++ b/makefile_conf/chain/oasys.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/685'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/685'"
 TICKER = "OAS"
 CHAIN_ID = 248
 APPNAME = "Oasys"
diff --git a/makefile_conf/chain/okc.mk b/makefile_conf/chain/okc.mk
deleted file mode 100644
index 13e0f50a7..000000000
--- a/makefile_conf/chain/okc.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "OKT"
-CHAIN_ID = 66
-APPNAME = "OKXChain"
diff --git a/makefile_conf/chain/poa.mk b/makefile_conf/chain/poa.mk
deleted file mode 100644
index 5590fc9d9..000000000
--- a/makefile_conf/chain/poa.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "POA"
-CHAIN_ID = 99
-APPNAME = "POA"
diff --git a/makefile_conf/chain/polygon.mk b/makefile_conf/chain/polygon.mk
deleted file mode 100644
index 25687985b..000000000
--- a/makefile_conf/chain/polygon.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "POL"
-CHAIN_ID = 137
-APPNAME = "Polygon"
diff --git a/makefile_conf/chain/shiden.mk b/makefile_conf/chain/shiden.mk
index 74bf66abd..8cbf11d00 100644
--- a/makefile_conf/chain/shiden.mk
+++ b/makefile_conf/chain/shiden.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/809'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/809'"
 TICKER = "SDN"
 CHAIN_ID = 336
 APPNAME = "Shiden EVM"
diff --git a/makefile_conf/chain/shyft.mk b/makefile_conf/chain/shyft.mk
deleted file mode 100644
index ae9899470..000000000
--- a/makefile_conf/chain/shyft.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH_APP_LOAD_PARAMS += "44'/60'"
-TICKER = "SHFT"
-CHAIN_ID = 7341
-APPNAME = "Shyft"
diff --git a/makefile_conf/chain/songbird.mk b/makefile_conf/chain/songbird.mk
index 7dc4b6f5f..157cfa2f9 100644
--- a/makefile_conf/chain/songbird.mk
+++ b/makefile_conf/chain/songbird.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/554'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/554'"
 TICKER = "SGB"
 CHAIN_ID = 19
 APPNAME = "Songbird"
diff --git a/makefile_conf/chain/tecracoin.mk b/makefile_conf/chain/tecracoin.mk
index fc34beb0c..23a87d88c 100644
--- a/makefile_conf/chain/tecracoin.mk
+++ b/makefile_conf/chain/tecracoin.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/554'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/554'"
 TICKER = "TCR"
 CHAIN_ID = 20531812
 APPNAME = "TecraCoin"
diff --git a/makefile_conf/chain/volta.mk b/makefile_conf/chain/volta.mk
index 1d3f51a59..136c5de02 100644
--- a/makefile_conf/chain/volta.mk
+++ b/makefile_conf/chain/volta.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/73799'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/73799'"
 TICKER = "VOLTA"
 CHAIN_ID = 73799
 APPNAME = "Volta"
diff --git a/makefile_conf/chain/xdcnetwork.mk b/makefile_conf/chain/xdcnetwork.mk
index 9a553969c..0de2ce325 100644
--- a/makefile_conf/chain/xdcnetwork.mk
+++ b/makefile_conf/chain/xdcnetwork.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/60'" "44'/550'"
+PATH_APP_LOAD_PARAMS += "44'/550'"
 TICKER = "XDC"
 CHAIN_ID = 50
 APPNAME = "XDC Network"
diff --git a/makefile_conf/features.mk b/makefile_conf/features.mk
index 59b707fce..8d1ab1ea3 100644
--- a/makefile_conf/features.mk
+++ b/makefile_conf/features.mk
@@ -1,11 +1,5 @@
 # Activate requested features
 # ---------------------------
-# Enables direct data signing without having to specify it in the settings. Useful when testing with speculos.
-ALLOW_DATA ?= 0
-ifneq ($(ALLOW_DATA),0)
-    DEFINES += HAVE_ALLOW_DATA
-endif
-
 # Bypass the signature verification for setExternalPlugin, setPlugin, provideERC20TokenInfo and provideNFTInfo calls
 BYPASS_SIGNATURES ?= 0
 ifneq ($(BYPASS_SIGNATURES),0)
@@ -56,10 +50,10 @@ endif
 
 # ENS
 ifneq ($(TARGET_NAME),TARGET_NANOS)
-    DEFINES += HAVE_DOMAIN_NAME
-    DOMAIN_NAME_TEST_KEY ?= 0
-    ifneq ($(DOMAIN_NAME_TEST_KEY),0)
-        DEFINES += HAVE_DOMAIN_NAME_TEST_KEY
+    DEFINES += HAVE_TRUSTED_NAME
+    TRUSTED_NAME_TEST_KEY ?= 0
+    ifneq ($(TRUSTED_NAME_TEST_KEY),0)
+        DEFINES += HAVE_TRUSTED_NAME_TEST_KEY
     endif
 endif
 
diff --git a/src/apdu_constants.h b/src/apdu_constants.h
index 471a26253..f322c89c3 100644
--- a/src/apdu_constants.h
+++ b/src/apdu_constants.h
@@ -1,6 +1,7 @@
 #ifndef _APDU_CONSTANTS_H_
 #define _APDU_CONSTANTS_H_
 
+#include "offsets.h"
 #include "shared_context.h"
 
 #define APP_FLAG_DATA_ALLOWED          0x01
@@ -33,100 +34,73 @@
 #define P2_EIP712_LEGACY_IMPLEM             0x00
 #define P2_EIP712_FULL_IMPLEM               0x01
 
-#define COMMON_CLA 0xB0
-
-#define APDU_RESPONSE_OK                      0x9000
+#define APDU_NO_RESPONSE                      0x0000
+#define APDU_RESPONSE_MODE_CHECK_FAILED       0x6001
+#define APDU_RESPONSE_TX_TYPE_NOT_SUPPORTED   0x6501
+#define APDU_RESPONSE_CHAINID_OUT_BUF_SMALL   0x6502
+#define APDU_RESPONSE_INTERNAL_ERROR          0x6800
+#define APDU_RESPONSE_SECURITY_NOT_SATISFIED  0x6982
+#define APDU_RESPONSE_WRONG_DATA_LENGTH       0x6983
+#define APDU_RESPONSE_PLUGIN_NOT_INSTALLED    0x6984
+#define APDU_RESPONSE_CONDITION_NOT_SATISFIED 0x6985
 #define APDU_RESPONSE_ERROR_NO_INFO           0x6a00
 #define APDU_RESPONSE_INVALID_DATA            0x6a80
 #define APDU_RESPONSE_INSUFFICIENT_MEMORY     0x6a84
-#define APDU_RESPONSE_INVALID_INS             0x6d00
-#define APDU_RESPONSE_INVALID_P1_P2           0x6b00
-#define APDU_RESPONSE_CONDITION_NOT_SATISFIED 0x6985
 #define APDU_RESPONSE_REF_DATA_NOT_FOUND      0x6a88
+#define APDU_RESPONSE_INVALID_P1_P2           0x6b00
+#define APDU_RESPONSE_INVALID_INS             0x6d00
+#define APDU_RESPONSE_INVALID_CLA             0x6e00
 #define APDU_RESPONSE_UNKNOWN                 0x6f00
+#define APDU_RESPONSE_OK                      0x9000
+#define APDU_RESPONSE_CMD_CODE_NOT_SUPPORTED  0x911c
 
-enum { OFFSET_CLA = 0, OFFSET_INS, OFFSET_P1, OFFSET_P2, OFFSET_LC, OFFSET_CDATA };
+uint16_t handleGetPublicKey(uint8_t p1,
+                            uint8_t p2,
+                            const uint8_t *dataBuffer,
+                            uint8_t dataLength,
+                            unsigned int *flags,
+                            unsigned int *tx);
+uint16_t handleProvideErc20TokenInformation(const uint8_t *workBuffer,
+                                            uint8_t dataLength,
+                                            unsigned int *tx);
+uint16_t handleProvideNFTInformation(const uint8_t *dataBuffer,
+                                     uint8_t dataLength,
+                                     unsigned int *tx);
+uint16_t handleSign(uint8_t p1,
+                    uint8_t p2,
+                    const uint8_t *dataBuffer,
+                    uint8_t dataLength,
+                    unsigned int *flags);
+uint16_t handleGetAppConfiguration(unsigned int *tx);
+uint16_t handleSignPersonalMessage(uint8_t p1,
+                                   const uint8_t *const payload,
+                                   uint8_t length,
+                                   unsigned int *flags);
+uint16_t handleSignEIP712Message_v0(uint8_t p1,
+                                    const uint8_t *dataBuffer,
+                                    uint8_t dataLength,
+                                    unsigned int *flags);
+
+uint16_t handleSetExternalPlugin(const uint8_t *workBuffer, uint8_t dataLength);
+
+uint16_t handleSetPlugin(const uint8_t *workBuffer, uint8_t dataLength);
+
+uint16_t handlePerformPrivacyOperation(uint8_t p1,
+                                       uint8_t p2,
+                                       const uint8_t *workBuffer,
+                                       uint8_t dataLength,
+                                       unsigned int *flags,
+                                       unsigned int *tx);
 
-#define ERR_APDU_EMPTY         0x6982
-#define ERR_APDU_SIZE_MISMATCH 0x6983
+#ifdef HAVE_ETH2
 
-void handleGetPublicKey(uint8_t p1,
-                        uint8_t p2,
-                        const uint8_t *dataBuffer,
-                        uint8_t dataLength,
-                        unsigned int *flags,
-                        unsigned int *tx);
-void handleProvideErc20TokenInformation(uint8_t p1,
-                                        uint8_t p2,
-                                        const uint8_t *workBuffer,
-                                        uint8_t dataLength,
-                                        unsigned int *flags,
-                                        unsigned int *tx);
-void handleProvideNFTInformation(uint8_t p1,
-                                 uint8_t p2,
-                                 const uint8_t *dataBuffer,
-                                 uint8_t dataLength,
-                                 unsigned int *flags,
-                                 unsigned int *tx);
-void handleSign(uint8_t p1,
-                uint8_t p2,
-                const uint8_t *dataBuffer,
-                uint8_t dataLength,
-                unsigned int *flags,
-                unsigned int *tx);
-void handleGetAppConfiguration(uint8_t p1,
-                               uint8_t p2,
-                               const uint8_t *dataBuffer,
-                               uint8_t dataLength,
-                               unsigned int *flags,
-                               unsigned int *tx);
-bool handleSignPersonalMessage(uint8_t p1,
-                               uint8_t p2,
-                               const uint8_t *const payload,
-                               uint8_t length);
-void handleSignEIP712Message_v0(uint8_t p1,
+uint16_t handleGetEth2PublicKey(uint8_t p1,
                                 uint8_t p2,
                                 const uint8_t *dataBuffer,
                                 uint8_t dataLength,
                                 unsigned int *flags,
                                 unsigned int *tx);
 
-void handleSetExternalPlugin(uint8_t p1,
-                             uint8_t p2,
-                             const uint8_t *workBuffer,
-                             uint8_t dataLength,
-                             unsigned int *flags,
-                             unsigned int *tx);
-
-void handleSetPlugin(uint8_t p1,
-                     uint8_t p2,
-                     const uint8_t *workBuffer,
-                     uint8_t dataLength,
-                     unsigned int *flags,
-                     unsigned int *tx);
-
-void handlePerformPrivacyOperation(uint8_t p1,
-                                   uint8_t p2,
-                                   const uint8_t *workBuffer,
-                                   uint8_t dataLength,
-                                   unsigned int *flags,
-                                   unsigned int *tx);
-
-#ifdef HAVE_ETH2
-
-void handleGetEth2PublicKey(uint8_t p1,
-                            uint8_t p2,
-                            const uint8_t *dataBuffer,
-                            uint8_t dataLength,
-                            unsigned int *flags,
-                            unsigned int *tx);
-void handleSetEth2WinthdrawalIndex(uint8_t p1,
-                                   uint8_t p2,
-                                   uint8_t *dataBuffer,
-                                   uint8_t dataLength,
-                                   unsigned int *flags,
-                                   unsigned int *tx);
-
 #endif
 
 extern uint16_t apdu_response_code;
diff --git a/src/common_ui.h b/src/common_ui.h
index 677863d47..e29874bbb 100644
--- a/src/common_ui.h
+++ b/src/common_ui.h
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include "ui_logic.h"
 
 void ui_idle(void);
 void ui_warning_blind_signing(void);
@@ -24,6 +25,7 @@ void ui_191_switch_to_question(void);
 
 // EIP-712
 void ui_712_start(void);
+void ui_712_start_unfiltered(void);
 void ui_712_switch_to_message(void);
 void ui_712_switch_to_sign(void);
 
diff --git a/src/ethUstream.c b/src/ethUstream.c
index 428adb5ed..6616efff7 100644
--- a/src/ethUstream.c
+++ b/src/ethUstream.c
@@ -25,7 +25,38 @@
 #define MAX_INT256  32
 #define MAX_ADDRESS 20
 
-void initTx(txContext_t *context,
+static bool check_fields(txContext_t *context, const char *name, uint32_t length) {
+    UNUSED(name);  // Just for the case where DEBUG is not enabled
+    if (context->currentFieldIsList) {
+        PRINTF("Invalid type for %s\n", name);
+        return false;
+    }
+    if ((length > 0) && (context->currentFieldLength > length)) {
+        PRINTF("Invalid length for %s\n", name);
+        return false;
+    }
+    return true;
+}
+
+static bool check_empty_list(txContext_t *context, const char *name) {
+    UNUSED(name);  // Just for the case where DEBUG is not enabled
+    if (!context->currentFieldIsList) {
+        PRINTF("Invalid type for %s\n", name);
+        return false;
+    }
+    return true;
+}
+
+static bool check_cmd_length(txContext_t *context, const char *name, uint32_t length) {
+    UNUSED(name);  // Just for the case where DEBUG is not enabled
+    if (context->commandLength < length) {
+        PRINTF("%s Underflow\n", name);
+        return false;
+    }
+    return true;
+}
+
+bool initTx(txContext_t *context,
             cx_sha3_t *sha3,
             txContent_t *content,
             ustreamProcess_t customProcessor,
@@ -36,14 +67,16 @@ void initTx(txContext_t *context,
     context->customProcessor = customProcessor;
     context->extra = extra;
     context->currentField = RLP_NONE + 1;
-    CX_ASSERT(cx_keccak_init_no_throw(context->sha3, 256));
+    if (cx_keccak_init_no_throw(context->sha3, 256) != CX_OK) {
+        return false;
+    }
+    return true;
 }
 
-uint8_t readTxByte(txContext_t *context) {
+static bool readTxByte(txContext_t *context, uint8_t *txByte) {
     uint8_t data;
-    if (context->commandLength < 1) {
-        PRINTF("readTxByte Underflow\n");
-        THROW(EXCEPTION);
+    if (check_cmd_length(context, "readTxByte", 1) == false) {
+        return false;
     }
     data = *context->workBuffer;
     context->workBuffer++;
@@ -52,194 +85,209 @@ uint8_t readTxByte(txContext_t *context) {
         context->currentFieldPos++;
     }
     if (!(context->processingField && context->fieldSingleByte)) {
-        CX_ASSERT(cx_hash_no_throw((cx_hash_t *) context->sha3, 0, &data, 1, NULL, 0));
+        if (cx_hash_no_throw((cx_hash_t *) context->sha3, 0, &data, 1, NULL, 0) != CX_OK) {
+            return false;
+        }
     }
-    return data;
+    *txByte = data;
+    return true;
 }
 
-void copyTxData(txContext_t *context, uint8_t *out, uint32_t length) {
-    if (context->commandLength < length) {
-        PRINTF("copyTxData Underflow\n");
-        THROW(EXCEPTION);
+bool copyTxData(txContext_t *context, uint8_t *out, uint32_t length) {
+    if (check_cmd_length(context, "copyTxData", length) == false) {
+        return false;
     }
     if (out != NULL) {
         memmove(out, context->workBuffer, length);
     }
     if (!(context->processingField && context->fieldSingleByte)) {
-        CX_ASSERT(
-            cx_hash_no_throw((cx_hash_t *) context->sha3, 0, context->workBuffer, length, NULL, 0));
+        if (cx_hash_no_throw((cx_hash_t *) context->sha3,
+                             0,
+                             context->workBuffer,
+                             length,
+                             NULL,
+                             0) != CX_OK) {
+            return false;
+        }
     }
     context->workBuffer += length;
     context->commandLength -= length;
     if (context->processingField) {
         context->currentFieldPos += length;
     }
+    return true;
 }
 
-static void processContent(txContext_t *context) {
+static bool processContent(txContext_t *context) {
     // Keep the full length for sanity checks, move to the next field
-    if (!context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_CONTENT\n");
-        THROW(EXCEPTION);
+    if (check_empty_list(context, "RLP_CONTENT") == false) {
+        return false;
     }
+
     context->dataLength = context->currentFieldLength;
     context->currentField++;
     context->processingField = false;
+    return true;
 }
 
-static void processAccessList(txContext_t *context) {
-    if (!context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_ACCESS_LIST\n");
-        THROW(EXCEPTION);
+static bool processAccessList(txContext_t *context) {
+    if (check_empty_list(context, "RLP_ACCESS_LIST") == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
-        copyTxData(context, NULL, copySize);
+        if (copyTxData(context, NULL, copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
-static void processChainID(txContext_t *context) {
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_CHAINID\n");
-        THROW(EXCEPTION);
-    }
-    if (context->currentFieldLength > MAX_INT256) {
-        PRINTF("Invalid length for RLP_CHAINID\n");
-        THROW(EXCEPTION);
+static bool processChainID(txContext_t *context) {
+    if (check_fields(context, "RLP_CHAINID", MAX_INT256) == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
-        copyTxData(context, context->content->chainID.value, copySize);
+        if (copyTxData(context, context->content->chainID.value, copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->content->chainID.length = context->currentFieldLength;
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
-static void processNonce(txContext_t *context) {
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_NONCE\n");
-        THROW(EXCEPTION);
-    }
-    if (context->currentFieldLength > MAX_INT256) {
-        PRINTF("Invalid length for RLP_NONCE\n");
-        THROW(EXCEPTION);
+static bool processNonce(txContext_t *context) {
+    if (check_fields(context, "RLP_NONCE", MAX_INT256) == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
-        copyTxData(context, context->content->nonce.value, copySize);
+        if (copyTxData(context, context->content->nonce.value, copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->content->nonce.length = context->currentFieldLength;
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
-static void processStartGas(txContext_t *context) {
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_STARTGAS\n");
-        THROW(EXCEPTION);
-    }
-    if (context->currentFieldLength > MAX_INT256) {
-        PRINTF("Invalid length for RLP_STARTGAS %d\n", context->currentFieldLength);
-        THROW(EXCEPTION);
+static bool processStartGas(txContext_t *context) {
+    if (check_fields(context, "RLP_STARTGAS", MAX_INT256) == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
-        copyTxData(context, context->content->startgas.value + context->currentFieldPos, copySize);
+        if (copyTxData(context,
+                       context->content->startgas.value + context->currentFieldPos,
+                       copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->content->startgas.length = context->currentFieldLength;
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
 // Alias over `processStartGas()`.
-static void processGasLimit(txContext_t *context) {
-    processStartGas(context);
+static bool processGasLimit(txContext_t *context) {
+    return processStartGas(context);
 }
 
-static void processGasprice(txContext_t *context) {
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_GASPRICE\n");
-        THROW(EXCEPTION);
-    }
-    if (context->currentFieldLength > MAX_INT256) {
-        PRINTF("Invalid length for RLP_GASPRICE\n");
-        THROW(EXCEPTION);
+static bool processGasprice(txContext_t *context) {
+    if (check_fields(context, "RLP_GASPRICE", MAX_INT256) == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
-        copyTxData(context, context->content->gasprice.value + context->currentFieldPos, copySize);
+        if (copyTxData(context,
+                       context->content->gasprice.value + context->currentFieldPos,
+                       copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->content->gasprice.length = context->currentFieldLength;
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
-static void processValue(txContext_t *context) {
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_VALUE\n");
-        THROW(EXCEPTION);
-    }
-    if (context->currentFieldLength > MAX_INT256) {
-        PRINTF("Invalid length for RLP_VALUE\n");
-        THROW(EXCEPTION);
+static bool processValue(txContext_t *context) {
+    if (check_fields(context, "RLP_VALUE", MAX_INT256) == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
-        copyTxData(context, context->content->value.value + context->currentFieldPos, copySize);
+        if (copyTxData(context,
+                       context->content->value.value + context->currentFieldPos,
+                       copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->content->value.length = context->currentFieldLength;
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
-static void processTo(txContext_t *context) {
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_TO\n");
-        THROW(EXCEPTION);
-    }
-    if (context->currentFieldLength > MAX_ADDRESS) {
-        PRINTF("Invalid length for RLP_TO\n");
-        THROW(EXCEPTION);
+static bool processTo(txContext_t *context) {
+    if (check_fields(context, "RLP_TO", MAX_ADDRESS) == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
-        copyTxData(context, context->content->destination + context->currentFieldPos, copySize);
+        if (copyTxData(context,
+                       context->content->destination + context->currentFieldPos,
+                       copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->content->destinationLength = context->currentFieldLength;
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
-static void processData(txContext_t *context) {
+static bool processData(txContext_t *context) {
     PRINTF("PROCESS DATA\n");
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_DATA\n");
-        THROW(EXCEPTION);
+    if (check_fields(context, "RLP_DATA", 0) == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
@@ -247,40 +295,40 @@ static void processData(txContext_t *context) {
         if (copySize == 1 && *context->workBuffer == 0x00) {
             context->content->dataPresent = false;
         }
-        copyTxData(context, NULL, copySize);
+        if (copyTxData(context, NULL, copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         PRINTF("incrementing field\n");
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
-static void processAndDiscard(txContext_t *context) {
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for Discarded field\n");
-        THROW(EXCEPTION);
+static bool processAndDiscard(txContext_t *context) {
+    if (check_fields(context, "Discarded field", 0) == false) {
+        return false;
     }
+
     if (context->currentFieldPos < context->currentFieldLength) {
         uint32_t copySize =
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
-        copyTxData(context, NULL, copySize);
+        if (copyTxData(context, NULL, copySize) == false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
-static void processV(txContext_t *context) {
-    if (context->currentFieldIsList) {
-        PRINTF("Invalid type for RLP_V\n");
-        THROW(EXCEPTION);
-    }
-
-    if (context->currentFieldLength > sizeof(context->content->v)) {
-        PRINTF("Invalid length for RLP_V\n");
-        THROW(EXCEPTION);
+static bool processV(txContext_t *context) {
+    if (check_fields(context, "RLP_V", sizeof(context->content->v)) == false) {
+        return false;
     }
 
     if (context->currentFieldPos < context->currentFieldLength) {
@@ -288,134 +336,138 @@ static void processV(txContext_t *context) {
             MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
         // Make sure we do not copy more than the size of v.
         copySize = MIN(copySize, sizeof(context->content->v));
-        copyTxData(context, context->content->v + context->currentFieldPos, copySize);
+        if (copyTxData(context, context->content->v + context->currentFieldPos, copySize) ==
+            false) {
+            return false;
+        }
     }
     if (context->currentFieldPos == context->currentFieldLength) {
         context->content->vLength = context->currentFieldLength;
         context->currentField++;
         context->processingField = false;
     }
+    return true;
 }
 
 static bool processEIP1559Tx(txContext_t *context) {
+    bool ret = false;
     switch (context->currentField) {
         case EIP1559_RLP_CONTENT: {
-            processContent(context);
+            ret = processContent(context);
             break;
         }
         case EIP1559_RLP_CHAINID: {
-            processChainID(context);
+            ret = processChainID(context);
             break;
         }
         case EIP1559_RLP_NONCE: {
-            processNonce(context);
+            ret = processNonce(context);
             break;
         }
         case EIP1559_RLP_MAX_FEE_PER_GAS: {
-            processGasprice(context);
+            ret = processGasprice(context);
             break;
         }
         case EIP1559_RLP_GASLIMIT: {
-            processGasLimit(context);
+            ret = processGasLimit(context);
             break;
         }
         case EIP1559_RLP_TO: {
-            processTo(context);
+            ret = processTo(context);
             break;
         }
         case EIP1559_RLP_VALUE: {
-            processValue(context);
+            ret = processValue(context);
             break;
         }
         case EIP1559_RLP_DATA: {
-            processData(context);
+            ret = processData(context);
             break;
         }
         case EIP1559_RLP_ACCESS_LIST: {
-            processAccessList(context);
+            ret = processAccessList(context);
             break;
         }
         case EIP1559_RLP_MAX_PRIORITY_FEE_PER_GAS:
-            processAndDiscard(context);
+            ret = processAndDiscard(context);
             break;
         default:
             PRINTF("Invalid RLP decoder context\n");
-            return true;
     }
-    return false;
+    return ret;
 }
 
 static bool processEIP2930Tx(txContext_t *context) {
+    bool ret = false;
     switch (context->currentField) {
         case EIP2930_RLP_CONTENT:
-            processContent(context);
+            ret = processContent(context);
             break;
         case EIP2930_RLP_CHAINID:
-            processChainID(context);
+            ret = processChainID(context);
             break;
         case EIP2930_RLP_NONCE:
-            processNonce(context);
+            ret = processNonce(context);
             break;
         case EIP2930_RLP_GASPRICE:
-            processGasprice(context);
+            ret = processGasprice(context);
             break;
         case EIP2930_RLP_GASLIMIT:
-            processGasLimit(context);
+            ret = processGasLimit(context);
             break;
         case EIP2930_RLP_TO:
-            processTo(context);
+            ret = processTo(context);
             break;
         case EIP2930_RLP_VALUE:
-            processValue(context);
+            ret = processValue(context);
             break;
         case EIP2930_RLP_DATA:
-            processData(context);
+            ret = processData(context);
             break;
         case EIP2930_RLP_ACCESS_LIST:
-            processAccessList(context);
+            ret = processAccessList(context);
             break;
         default:
             PRINTF("Invalid RLP decoder context\n");
-            return true;
     }
-    return false;
+    return ret;
 }
 
 static bool processLegacyTx(txContext_t *context) {
+    bool ret = false;
     switch (context->currentField) {
         case LEGACY_RLP_CONTENT:
-            processContent(context);
+            ret = processContent(context);
             break;
         case LEGACY_RLP_NONCE:
-            processNonce(context);
+            ret = processNonce(context);
             break;
         case LEGACY_RLP_GASPRICE:
-            processGasprice(context);
+            ret = processGasprice(context);
             break;
         case LEGACY_RLP_STARTGAS:
-            processStartGas(context);
+            ret = processStartGas(context);
             break;
         case LEGACY_RLP_TO:
-            processTo(context);
+            ret = processTo(context);
             break;
         case LEGACY_RLP_VALUE:
-            processValue(context);
+            ret = processValue(context);
             break;
         case LEGACY_RLP_DATA:
-            processData(context);
+            ret = processData(context);
             break;
         case LEGACY_RLP_R:
         case LEGACY_RLP_S:
-            processAndDiscard(context);
+            ret = processAndDiscard(context);
             break;
         case LEGACY_RLP_V:
-            processV(context);
+            ret = processV(context);
             break;
         default:
             PRINTF("Invalid RLP decoder context\n");
-            return true;
     }
-    return false;
+    return ret;
 }
 
 static parserStatus_e parseRLP(txContext_t *context) {
@@ -424,7 +476,9 @@ static parserStatus_e parseRLP(txContext_t *context) {
     while (context->commandLength != 0) {
         bool valid;
         // Feed the RLP buffer until the length can be decoded
-        context->rlpBuffer[context->rlpBufferPos++] = readTxByte(context);
+        if (readTxByte(context, &context->rlpBuffer[context->rlpBufferPos++]) == false) {
+            return USTREAM_FAULT;
+        }
         if (rlpCanDecode(context->rlpBuffer, context->rlpBufferPos, &valid)) {
             // Can decode now, if valid
             if (!valid) {
@@ -519,28 +573,21 @@ static parserStatus_e processTxInternal(txContext_t *context) {
         if (customStatus == CUSTOM_NOT_HANDLED) {
             PRINTF("Current field: %d\n", context->currentField);
             switch (context->txType) {
-                bool fault;
                 case LEGACY:
-                    fault = processLegacyTx(context);
-                    if (fault) {
+                    if (processLegacyTx(context) == false) {
                         return USTREAM_FAULT;
-                    } else {
-                        break;
                     }
+                    break;
                 case EIP2930:
-                    fault = processEIP2930Tx(context);
-                    if (fault) {
+                    if (processEIP2930Tx(context) == false) {
                         return USTREAM_FAULT;
-                    } else {
-                        break;
                     }
+                    break;
                 case EIP1559:
-                    fault = processEIP1559Tx(context);
-                    if (fault) {
+                    if (processEIP1559Tx(context) == false) {
                         return USTREAM_FAULT;
-                    } else {
-                        break;
                     }
+                    break;
                 default:
                     PRINTF("Transaction type %d is not supported\n", context->txType);
                     return USTREAM_FAULT;
@@ -551,36 +598,11 @@ static parserStatus_e processTxInternal(txContext_t *context) {
 }
 
 parserStatus_e processTx(txContext_t *context, const uint8_t *buffer, uint32_t length) {
-    parserStatus_e result;
-    BEGIN_TRY {
-        TRY {
-            context->workBuffer = buffer;
-            context->commandLength = length;
-            result = processTxInternal(context);
-            PRINTF("result: %d\n", result);
-        }
-        CATCH_OTHER(e) {
-            result = USTREAM_FAULT;
-        }
-        FINALLY {
-        }
-    }
-    END_TRY;
-    return result;
+    context->workBuffer = buffer;
+    context->commandLength = length;
+    return processTxInternal(context);
 }
 
 parserStatus_e continueTx(txContext_t *context) {
-    parserStatus_e result;
-    BEGIN_TRY {
-        TRY {
-            result = processTxInternal(context);
-        }
-        CATCH_OTHER(e) {
-            result = USTREAM_FAULT;
-        }
-        FINALLY {
-        }
-    }
-    END_TRY;
-    return result;
+    return processTxInternal(context);
 }
diff --git a/src/ethUstream.h b/src/ethUstream.h
index b27e490b9..3548af985 100644
--- a/src/ethUstream.h
+++ b/src/ethUstream.h
@@ -126,12 +126,11 @@ typedef struct txContext_t {
     uint8_t txType;
 } txContext_t;
 
-void initTx(txContext_t *context,
+bool initTx(txContext_t *context,
             cx_sha3_t *sha3,
             txContent_t *content,
             ustreamProcess_t customProcessor,
             void *extra);
 parserStatus_e processTx(txContext_t *context, const uint8_t *buffer, uint32_t length);
 parserStatus_e continueTx(txContext_t *context);
-void copyTxData(txContext_t *context, uint8_t *out, uint32_t length);
-uint8_t readTxByte(txContext_t *context);
+bool copyTxData(txContext_t *context, uint8_t *out, uint32_t length);
diff --git a/src/eth_plugin_handler.c b/src/eth_plugin_handler.c
index 475a2a40f..8150eb730 100644
--- a/src/eth_plugin_handler.c
+++ b/src/eth_plugin_handler.c
@@ -4,6 +4,7 @@
 #include "plugin_utils.h"
 #include "shared_context.h"
 #include "network.h"
+#include "cmd_setPlugin.h"
 
 void eth_plugin_prepare_init(ethPluginInitContract_t *init,
                              const uint8_t *selector,
@@ -153,10 +154,13 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
             break;
     }
 
-    // Do not handle a plugin if running in swap mode
     if (G_called_from_swap && (contractAddress != NULL)) {
-        PRINTF("eth_plug_init aborted in swap mode\n");
-        return 0;
+        PRINTF("contractAddress == %.*H\n", 20, contractAddress);
+        PRINTF("selector == %.*H\n", 20, contractAddress);
+        PRINTF("Fallback on swap_with_calldata plugin\n");
+        set_swap_with_calldata_plugin_type();
+        dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
+        contractAddress = NULL;
     }
 
     eth_plugin_result_t status = ETH_PLUGIN_RESULT_UNAVAILABLE;
@@ -207,6 +211,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
                 (uint8_t *) &dataContext.tokenContext.pluginContext;
             ((ethPluginInitContract_t *) parameter)->pluginContextLength =
                 sizeof(dataContext.tokenContext.pluginContext);
+            ((ethPluginInitContract_t *) parameter)->bip32 = &tmpCtx.transactionContext.bip32;
             break;
         case ETH_PLUGIN_PROVIDE_PARAMETER:
             PRINTF("-- PLUGIN PROVIDE PARAMETER --\n");
@@ -271,6 +276,10 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
             END_TRY;
             break;
         }
+        case SWAP_WITH_CALLDATA: {
+            swap_with_calldata_plugin_call(method, parameter);
+            break;
+        }
 #ifdef HAVE_NFT_SUPPORT
         case ERC721: {
             erc721_plugin_call(method, parameter);
diff --git a/src/eth_plugin_internal.h b/src/eth_plugin_internal.h
index 14eecea58..40466ac30 100644
--- a/src/eth_plugin_internal.h
+++ b/src/eth_plugin_internal.h
@@ -7,6 +7,7 @@
 
 void erc721_plugin_call(int message, void* parameters);
 void erc1155_plugin_call(int message, void* parameters);
+void swap_with_calldata_plugin_call(int message, void* parameters);
 
 typedef bool (*const PluginAvailableCheck)(void);
 typedef void (*PluginCall)(int, void*);
diff --git a/src/swap_utils.c b/src/eth_swap_utils.c
similarity index 98%
rename from src/swap_utils.c
rename to src/eth_swap_utils.c
index 7774b7554..00410434b 100644
--- a/src/swap_utils.c
+++ b/src/eth_swap_utils.c
@@ -20,7 +20,7 @@
 #include <stdbool.h>
 
 #include "asset_info.h"
-#include "swap_utils.h"
+#include "eth_swap_utils.h"
 
 bool parse_swap_config(const uint8_t *config,
                        uint8_t config_len,
diff --git a/src/swap_utils.h b/src/eth_swap_utils.h
similarity index 58%
rename from src/swap_utils.h
rename to src/eth_swap_utils.h
index 76ca90e56..17f9add45 100644
--- a/src/swap_utils.h
+++ b/src/eth_swap_utils.h
@@ -18,9 +18,24 @@
 #pragma once
 
 #include <stdint.h>
+#include "swap_lib_calls.h"
+#include "chainConfig.h"
+#include "caller_api.h"
 
-bool parse_swap_config(const uint8_t* config,
+typedef struct eth_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;
+    };
+} eth_libargs_t;
+
+bool parse_swap_config(const uint8_t *config,
                        uint8_t config_len,
-                       char* ticker,
-                       uint8_t* decimals,
-                       uint64_t* chain_id);
+                       char *ticker,
+                       uint8_t *decimals,
+                       uint64_t *chain_id);
diff --git a/src/extra_tokens.c b/src/extra_tokens.c
deleted file mode 100644
index 9faefcbd3..000000000
--- a/src/extra_tokens.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*******************************************************************************
- *   Ledger Ethereum App
- *   (c) 2016-2019 Ledger
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- ********************************************************************************/
-
-#ifdef HAVE_TOKENS_EXTRA_LIST
-
-#include "extra_tokens.h"
-
-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",
-     6},
-    {{0x1c, 0x0f, 0x17, 0x43, 0x67, 0x40, 0xbf, 0xb9, 0x2c, 0x10,
-      0x70, 0xee, 0x86, 0x32, 0x2d, 0xe8, 0x90, 0x83, 0x7c, 0x6a},
-     "tUSDT",
-     6},
-    {{0xcd, 0x07, 0x7a, 0xbe, 0xdd, 0x83, 0x1a, 0x34, 0x43, 0xff,
-      0xbe, 0x24, 0xfb, 0x76, 0x66, 0x1b, 0xbb, 0x17, 0xeb, 0x69},
-     "tZRX",
-     18},
-    {{0x40, 0xd8, 0x97, 0x85, 0x00, 0xbf, 0x68, 0x32, 0x4a, 0x51,
-      0x53, 0x3c, 0xd6, 0xa2, 0x1e, 0x3e, 0x59, 0xbe, 0x32, 0x4a},
-     "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",
-     6},
-    {{0xc1, 0xd5, 0x79, 0xeb, 0xff, 0x7c, 0x0f, 0x6c, 0xfd, 0x9a,
-      0xd5, 0xfb, 0x26, 0x7f, 0xec, 0x73, 0xbe, 0x70, 0xc8, 0xf7},
-     "tBTC",
-     18},
-    {{0xa8, 0xf3, 0x14, 0x4f, 0xea, 0x2c, 0x37, 0x5a, 0xd0, 0x58,
-      0xec, 0x12, 0x09, 0x9a, 0x5a, 0x21, 0xa2, 0x6f, 0xe9, 0x96},
-     "tDVF",
-     18},
-    {{0x4c, 0xda, 0xbe, 0xc1, 0x2a, 0x39, 0x7f, 0xb6, 0xef, 0xaf,
-      0x46, 0x13, 0xd5, 0xdf, 0xd7, 0x9b, 0x30, 0x9a, 0xe9, 0xfa},
-     "tXDVF",
-     18},
-
-};
-
-#endif
diff --git a/src/extra_tokens.h b/src/extra_tokens.h
deleted file mode 100644
index f6b012c9a..000000000
--- a/src/extra_tokens.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*******************************************************************************
- *   Ledger Ethereum App
- *   (c) 2016-2019 Ledger
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- ********************************************************************************/
-
-#pragma once
-
-#include "asset_info.h"
-
-#ifdef HAVE_TOKENS_EXTRA_LIST
-
-#define NUM_TOKENS_EXTRA 8
-
-extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
-
-#endif
diff --git a/src/handle_check_address.c b/src/handle_check_address.c
index e41bb7329..cf9e4f9c6 100644
--- a/src/handle_check_address.c
+++ b/src/handle_check_address.c
@@ -7,40 +7,34 @@
 
 #define ZERO(x) explicit_bzero(&x, sizeof(x))
 
-void handle_check_address(check_address_parameters_t* params, const chain_config_t* chain_config) {
+uint16_t handle_check_address(check_address_parameters_t* params, chain_config_t* chain_config) {
     params->result = 0;
     PRINTF("Params on the address %d\n", (unsigned int) params);
     PRINTF("Address to check %s\n", params->address_to_check);
     PRINTF("Inside handle_check_address\n");
     if (params->address_to_check == 0) {
         PRINTF("Address to check == 0\n");
-        return;
+        return APDU_RESPONSE_OK;
     }
 
-    const uint8_t* bip32_path_ptr = params->address_parameters;
-    uint8_t bip32PathLength = *(bip32_path_ptr++);
-    uint32_t bip32Path[MAX_BIP32_PATH];
     char address[51];
     uint8_t raw_pubkey[65];
-
-    if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH) ||
-        (bip32PathLength * 4 != params->address_parameters_length - 1)) {
+    cx_err_t error = CX_INTERNAL_ERROR;
+    bip32_path_t bip32;
+    bip32.length = params->address_parameters[0];
+    if (bip32_path_read(params->address_parameters + 1,
+                        params->address_parameters_length,
+                        bip32.path,
+                        bip32.length) == false) {
         PRINTF("Invalid path\n");
-        return;
-    }
-    for (uint8_t i = 0; i < bip32PathLength; i++) {
-        bip32Path[i] = U4BE(bip32_path_ptr, 0);
-        bip32_path_ptr += 4;
-    }
-
-    if (bip32_derive_get_pubkey_256(CX_CURVE_256K1,
-                                    bip32Path,
-                                    bip32PathLength,
-                                    raw_pubkey,
-                                    NULL,
-                                    CX_SHA512) != CX_OK) {
-        THROW(APDU_RESPONSE_UNKNOWN);
+        return APDU_RESPONSE_INVALID_DATA;
     }
+    CX_CHECK(bip32_derive_get_pubkey_256(CX_CURVE_256K1,
+                                         bip32.path,
+                                         bip32.length,
+                                         raw_pubkey,
+                                         NULL,
+                                         CX_SHA512));
 
     getEthAddressStringFromRawKey((const uint8_t*) raw_pubkey, address, chain_config->chainId);
 
@@ -55,4 +49,7 @@ void handle_check_address(check_address_parameters_t* params, const chain_config
         PRINTF("Addresses match\n");
         params->result = 1;
     }
+    error = APDU_RESPONSE_OK;
+end:
+    return error;
 }
diff --git a/src/handle_check_address.h b/src/handle_check_address.h
index 89a554136..ec3dfa999 100644
--- a/src/handle_check_address.h
+++ b/src/handle_check_address.h
@@ -4,7 +4,7 @@
 #include "swap_lib_calls.h"
 #include "chainConfig.h"
 
-void handle_check_address(check_address_parameters_t* check_address_params,
-                          const chain_config_t* chain_config);
+uint16_t handle_check_address(check_address_parameters_t* check_address_params,
+                              chain_config_t* chain_config);
 
 #endif  // _HANDLE_CHECK_ADDRESS_H_
diff --git a/src/handle_get_printable_amount.c b/src/handle_get_printable_amount.c
index 5a70e881c..5b8d1f6c0 100644
--- a/src/handle_get_printable_amount.c
+++ b/src/handle_get_printable_amount.c
@@ -1,16 +1,17 @@
 #include <stdint.h>
 #include <os.h>
 
-#include "swap_utils.h"
+#include "eth_swap_utils.h"
 #include "handle_get_printable_amount.h"
 #include "shared_context.h"
 #include "common_utils.h"
 #include "uint256.h"
 #include "string.h"
 #include "network.h"
+#include "apdu_constants.h"
 
-void handle_get_printable_amount(get_printable_amount_parameters_t* params,
-                                 chain_config_t* config) {
+uint16_t handle_get_printable_amount(get_printable_amount_parameters_t* params,
+                                     chain_config_t* config) {
     char ticker[MAX_TICKER_LEN];
     uint8_t decimals;
     uint64_t chain_id = 0;
@@ -18,7 +19,7 @@ void handle_get_printable_amount(get_printable_amount_parameters_t* params,
     memset(params->printable_amount, 0, sizeof(params->printable_amount));
     if (params->amount_length > 32) {
         PRINTF("Amount is too big, 32 bytes max but buffer has %u bytes", params->amount_length);
-        return;
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     if (!parse_swap_config(params->coin_configuration,
@@ -27,7 +28,7 @@ void handle_get_printable_amount(get_printable_amount_parameters_t* params,
                            &decimals,
                            &chain_id)) {
         PRINTF("Error while parsing config\n");
-        return;
+        return APDU_RESPONSE_INVALID_DATA;
     }
     // If the amount is a fee, the ticker should be the chain's native currency
     if (params->is_fee) {
@@ -47,5 +48,5 @@ void handle_get_printable_amount(get_printable_amount_parameters_t* params,
                         sizeof(params->printable_amount))) {
         memset(params->printable_amount, 0, sizeof(params->printable_amount));
     }
-    return;
+    return APDU_RESPONSE_OK;
 }
diff --git a/src/handle_get_printable_amount.h b/src/handle_get_printable_amount.h
index b81729404..706de9f50 100644
--- a/src/handle_get_printable_amount.h
+++ b/src/handle_get_printable_amount.h
@@ -4,7 +4,7 @@
 #include "swap_lib_calls.h"
 #include "chainConfig.h"
 
-void handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params,
-                                 chain_config_t* config);
+uint16_t handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params,
+                                     chain_config_t* config);
 
 #endif  // _HANDLE_GET_PRINTABLE_AMOUNT_H_
diff --git a/src/handle_swap_sign_transaction.c b/src/handle_swap_sign_transaction.c
index 2ea314af7..7ac6d6f36 100644
--- a/src/handle_swap_sign_transaction.c
+++ b/src/handle_swap_sign_transaction.c
@@ -1,7 +1,7 @@
 #include "os_io_seproxyhal.h"
 #include "os.h"
 #include "ux.h"
-#include "swap_utils.h"
+#include "eth_swap_utils.h"
 #include "handle_swap_sign_transaction.h"
 #include "shared_context.h"
 #include "common_utils.h"
@@ -10,15 +10,37 @@
 #include "nbgl_use_case.h"
 #endif  // HAVE_NBGL
 
+// Remember if we have been started by the Exchange application or not
+bool G_called_from_swap;
+
+// Set this boolean when a transaction is signed in Swap mode. Safety against double sign
+bool G_swap_response_ready;
+
 // Save the BSS address where we will write the return value when finished
 static uint8_t* G_swap_sign_return_value_address;
 
+// Standard or crosschain swap type
+swap_mode_t G_swap_mode;
+
+// On crosschain swap, save the hash promised by the partner
+uint8_t G_swap_crosschain_hash[CX_SHA256_SIZE];
+
+typedef enum extra_id_type_e {
+    EXTRA_ID_TYPE_NATIVE,
+    EXTRA_ID_TYPE_EVM_CALLDATA,
+    // There are others but they are not relevant for the Ethereum application
+} extra_id_type_t;
+
 bool copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params,
                                  const chain_config_t* config) {
     // first copy parameters to stack, and then to global data.
     // We need this "trick" as the input data position can overlap with app-ethereum globals
     txStringProperties_t stack_data;
+    uint8_t destination_address_extra_data[CX_SHA256_SIZE + 1];
+
     memset(&stack_data, 0, sizeof(stack_data));
+    memset(destination_address_extra_data, 0, sizeof(destination_address_extra_data));
+
     strlcpy(stack_data.toAddress,
             sign_transaction_params->destination_address,
             sizeof(stack_data.toAddress));
@@ -28,6 +50,12 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
         return false;
     }
 
+    if (sign_transaction_params->destination_address_extra_id != NULL) {
+        memcpy(destination_address_extra_data,
+               sign_transaction_params->destination_address_extra_id,
+               sizeof(destination_address_extra_data));
+    }
+
     char ticker[MAX_TICKER_LEN];
     uint8_t decimals;
     uint64_t chain_id = 0;
@@ -71,6 +99,31 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
     G_swap_sign_return_value_address = &sign_transaction_params->result;
     // Commit the values read from exchange to the clean global space
 
+    // if destination_address_extra_id is given, we use the first byte to determine if we use the
+    // normal swap protocol, or the one for cross-chain swaps
+    switch (destination_address_extra_data[0]) {
+        case EXTRA_ID_TYPE_NATIVE:
+            G_swap_mode = SWAP_MODE_STANDARD;
+            PRINTF("Standard swap\n");
+
+            // we don't use the payin_extra_id field in this mode
+            explicit_bzero(G_swap_crosschain_hash, sizeof(G_swap_crosschain_hash));
+            break;
+        case EXTRA_ID_TYPE_EVM_CALLDATA:
+            G_swap_mode = SWAP_MODE_CROSSCHAIN_PENDING_CHECK;
+
+            memcpy(G_swap_crosschain_hash,
+                   destination_address_extra_data + 1,
+                   sizeof(G_swap_crosschain_hash));
+
+            PRINTF("Crosschain swap with hash: %.*H\n", CX_SHA256_SIZE, G_swap_crosschain_hash);
+            break;
+        default:
+            // We can't return errors from here, we remember that we have an issue to report later
+            PRINTF("Invalid or unknown swap protocol\n");
+            G_swap_mode = SWAP_MODE_ERROR;
+    }
+
     memcpy(&strings.common, &stack_data, sizeof(stack_data));
     return true;
 }
@@ -81,35 +134,23 @@ void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_succes
 }
 
 void __attribute__((noreturn)) handle_swap_sign_transaction(const chain_config_t* config) {
-#ifdef HAVE_NBGL
-    // On Stax, display a spinner at startup
-    UX_INIT();
-    nbgl_useCaseSpinner("Signing");
-#endif  // HAVE_NBGL
-
     chainConfig = config;
     reset_app_context();
     G_called_from_swap = true;
     G_swap_response_ready = false;
-    io_seproxyhal_init();
 
-    if (N_storage.initialized != 0x01) {
-        internalStorage_t storage;
-        explicit_bzero(&storage, sizeof(storage));
-        storage.initialized = true;
-        nvm_write((void*) &N_storage, (void*) &storage, sizeof(internalStorage_t));
-    }
+    common_app_init();
+
+    storage_init();
+
+#ifdef HAVE_NBGL
+    nbgl_useCaseSpinner("Signing");
+#endif  // HAVE_NBGL
 
-    PRINTF("USB power ON/OFF\n");
-    USB_power(0);
-    USB_power(1);
-#ifdef HAVE_BLE
-    // grab the current plane mode setting
-    G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
-    BLE_power(0, NULL);
-    BLE_power(1, NULL);
-#endif  // HAVE_BLE
     app_main();
+
     // Failsafe
-    os_sched_exit(-1);
+    app_exit();
+    while (1)
+        ;
 }
diff --git a/src/ledger_pki.c b/src/ledger_pki.c
new file mode 100644
index 000000000..65d2bb38d
--- /dev/null
+++ b/src/ledger_pki.c
@@ -0,0 +1,76 @@
+#include "apdu_constants.h"
+#include "public_keys.h"
+#ifdef HAVE_LEDGER_PKI
+#include "os_pki.h"
+#endif
+
+#define KEY_USAGE_STR(x)                                                               \
+    (x == CERTIFICATE_PUBLIC_KEY_USAGE_GENUINE_CHECK          ? "GENUINE_CHECK"        \
+     : x == CERTIFICATE_PUBLIC_KEY_USAGE_EXCHANGE_PAYLOAD     ? "EXCHANGE_PAYLOAD"     \
+     : x == CERTIFICATE_PUBLIC_KEY_USAGE_NFT_METADATA         ? "NFT_METADATA"         \
+     : x == CERTIFICATE_PUBLIC_KEY_USAGE_TRUSTED_NAME         ? "TRUSTED_NAME"         \
+     : x == CERTIFICATE_PUBLIC_KEY_USAGE_BACKUP_PROVIDER      ? "BACKUP_PROVIDER"      \
+     : x == CERTIFICATE_PUBLIC_KEY_USAGE_RECOVER_ORCHESTRATOR ? "RECOVER_ORCHESTRATOR" \
+     : x == CERTIFICATE_PUBLIC_KEY_USAGE_PLUGIN_METADATA      ? "PLUGIN_METADATA"      \
+     : x == CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META            ? "COIN_META"            \
+     : x == CERTIFICATE_PUBLIC_KEY_USAGE_SEED_ID_AUTH         ? "SEED_ID_AUTH"         \
+                                                              : "Unknown")
+
+int check_signature_with_pubkey(const char *tag,
+                                uint8_t *buffer,
+                                const uint8_t bufLen,
+                                const uint8_t *PubKey,
+                                const uint8_t keyLen,
+#ifdef HAVE_LEDGER_PKI
+                                const uint8_t keyUsageExp,
+#endif
+                                uint8_t *signature,
+                                const uint8_t sigLen) {
+    UNUSED(tag);
+    cx_ecfp_public_key_t verif_key = {0};
+    cx_err_t error = CX_INTERNAL_ERROR;
+#ifdef HAVE_LEDGER_PKI
+    uint8_t key_usage = 0;
+    size_t trusted_name_len = 0;
+    uint8_t trusted_name[CERTIFICATE_TRUSTED_NAME_MAXLEN] = {0};
+    cx_ecfp_384_public_key_t public_key = {0};
+#endif
+
+    PRINTF(
+        "[%s] "
+        "=======================================================================================\n",
+        tag);
+#ifdef HAVE_LEDGER_PKI
+    error = os_pki_get_info(&key_usage, trusted_name, &trusted_name_len, &public_key);
+    if ((error == 0) && (key_usage == keyUsageExp)) {
+        PRINTF("[%s] Certificate '%s' loaded for usage 0x%x (%s)\n",
+               tag,
+               trusted_name,
+               key_usage,
+               KEY_USAGE_STR(key_usage));
+
+        // Checking the signature with PKI
+        if (!os_pki_verify(buffer, bufLen, signature, sigLen)) {
+            PRINTF("%s: Invalid signature\n", tag);
+#ifndef HAVE_BYPASS_SIGNATURES
+            error = APDU_RESPONSE_INVALID_DATA;
+            goto end;
+#endif
+        }
+    } else
+#endif
+    {
+        PRINTF("[%s] ********** No certificate loaded. Using legacy path **********\n", tag);
+        CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, PubKey, keyLen, &verif_key));
+        if (!cx_ecdsa_verify_no_throw(&verif_key, buffer, bufLen, signature, sigLen)) {
+            PRINTF("%s: Invalid signature\n", tag);
+#ifndef HAVE_BYPASS_SIGNATURES
+            error = APDU_RESPONSE_INVALID_DATA;
+            goto end;
+#endif
+        }
+    }
+    error = CX_OK;
+end:
+    return error;
+}
diff --git a/src/main.c b/src/main.c
index f44632c8f..0a6793f65 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,26 +20,22 @@
 #include "common_ui.h"
 
 #include "os_io_seproxyhal.h"
+#include "io.h"
 
+#include "parser.h"
 #include "glyphs.h"
 #include "common_utils.h"
 
-#include "swap_lib_calls.h"
+#include "eth_swap_utils.h"
 #include "handle_swap_sign_transaction.h"
 #include "handle_get_printable_amount.h"
 #include "handle_check_address.h"
 #include "commands_712.h"
 #include "challenge.h"
-#include "domain_name.h"
+#include "trusted_name.h"
 #include "crypto_helpers.h"
 #include "manage_asset_info.h"
 
-unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
-
-void ui_idle(void);
-
-uint32_t set_result_get_publicKey(void);
-
 tmpCtx_t tmpCtx;
 txContext_t txContext;
 tmpContent_t tmpContent;
@@ -49,8 +45,6 @@ cx_sha3_t global_sha3;
 
 uint8_t appState;
 uint16_t apdu_response_code;
-bool G_called_from_swap;
-bool G_swap_response_ready;
 pluginType_t pluginType;
 
 #ifdef HAVE_ETH2
@@ -59,8 +53,6 @@ uint32_t eth2WithdrawalIndex;
 #endif
 
 #include "ux.h"
-ux_state_t G_ux;
-bolos_ux_params_t G_ux_params;
 
 const internalStorage_t N_storage_real;
 
@@ -84,35 +76,19 @@ void reset_app_context() {
     memset((uint8_t *) &tmpContent, 0, sizeof(tmpContent));
 }
 
-void io_seproxyhal_send_status(uint32_t sw) {
-    G_io_apdu_buffer[0] = ((sw >> 8) & 0xff);
-    G_io_apdu_buffer[1] = (sw & 0xff);
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
-}
-
-unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
-    switch (channel & ~(IO_FLAGS)) {
-        case CHANNEL_KEYBOARD:
-            break;
-
-        // multiplexed io exchange over a SPI channel and TLV encapsulated protocol
-        case CHANNEL_SPI:
-            if (tx_len) {
-                io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
-
-                if (channel & IO_RESET_AFTER_REPLIED) {
-                    reset();
-                }
-                return 0;  // nothing received from the master so far (it's a tx
-                           // transaction)
-            } else {
-                return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
-            }
-
-        default:
-            THROW(INVALID_PARAMETER);
+uint16_t io_seproxyhal_send_status(uint16_t sw, uint32_t tx, bool reset, bool idle) {
+    uint16_t err = 0;
+    if (reset) {
+        reset_app_context();
     }
-    return 0;
+    U2BE_ENCODE(G_io_apdu_buffer, tx, sw);
+    tx += 2;
+    err = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
+    if (idle) {
+        // Display back the original UX
+        ui_idle();
+    }
+    return err;
 }
 
 const uint8_t *parseBip32(const uint8_t *dataBuffer, uint8_t *dataLength, bip32_path_t *bip32) {
@@ -123,11 +99,6 @@ const uint8_t *parseBip32(const uint8_t *dataBuffer, uint8_t *dataLength, bip32_
 
     bip32->length = *dataBuffer;
 
-    if (bip32->length < 0x1 || bip32->length > MAX_BIP32_PATH) {
-        PRINTF("Invalid bip32\n");
-        return NULL;
-    }
-
     dataBuffer++;
     (*dataLength)--;
 
@@ -136,244 +107,141 @@ const uint8_t *parseBip32(const uint8_t *dataBuffer, uint8_t *dataLength, bip32_
         return NULL;
     }
 
-    for (uint8_t i = 0; i < bip32->length; i++) {
-        bip32->path[i] = U4BE(dataBuffer, 0);
-        dataBuffer += sizeof(uint32_t);
-        *dataLength -= sizeof(uint32_t);
+    if (bip32_path_read(dataBuffer, (size_t) dataLength, bip32->path, (size_t) bip32->length) ==
+        false) {
+        PRINTF("Invalid Path data\n");
+        return NULL;
     }
+    dataBuffer += bip32->length * sizeof(uint32_t);
+    *dataLength -= bip32->length * sizeof(uint32_t);
 
     return dataBuffer;
 }
 
-void handleApdu(unsigned int *flags, unsigned int *tx) {
-    unsigned short sw = 0;
+static uint16_t handleApdu(command_t *cmd, uint32_t *flags, uint32_t *tx) {
+    uint16_t sw = APDU_NO_RESPONSE;
 
-    BEGIN_TRY {
-        TRY {
-            if (G_io_apdu_buffer[OFFSET_CLA] != CLA) {
-                THROW(0x6E00);
-            }
+#ifndef HAVE_LEDGER_PKI
+    if ((cmd->cla == 0xB0) && (cmd->ins == 0x06)) {
+        // Ledger-PKI APDU not yet caught by the running OS.
+        // Command code not supported
+        PRINTF("Ledger-PKI not yet supported!\n");
+        return APDU_RESPONSE_CMD_CODE_NOT_SUPPORTED;
+    }
+#endif  // HAVE_LEDGER_PKI
 
-            switch (G_io_apdu_buffer[OFFSET_INS]) {
-                case INS_GET_PUBLIC_KEY:
-                    forget_known_assets();
-                    handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1],
-                                       G_io_apdu_buffer[OFFSET_P2],
-                                       G_io_apdu_buffer + OFFSET_CDATA,
-                                       G_io_apdu_buffer[OFFSET_LC],
-                                       flags,
-                                       tx);
-                    break;
+    if (cmd->cla != CLA) {
+        return APDU_RESPONSE_INVALID_CLA;
+    }
 
-                case INS_PROVIDE_ERC20_TOKEN_INFORMATION:
-                    handleProvideErc20TokenInformation(G_io_apdu_buffer[OFFSET_P1],
-                                                       G_io_apdu_buffer[OFFSET_P2],
-                                                       G_io_apdu_buffer + OFFSET_CDATA,
-                                                       G_io_apdu_buffer[OFFSET_LC],
-                                                       flags,
-                                                       tx);
-                    break;
+    switch (cmd->ins) {
+        case INS_GET_PUBLIC_KEY:
+            forget_known_assets();
+            sw = handleGetPublicKey(cmd->p1, cmd->p2, cmd->data, cmd->lc, flags, tx);
+            break;
+
+        case INS_PROVIDE_ERC20_TOKEN_INFORMATION:
+            sw = handleProvideErc20TokenInformation(cmd->data, cmd->lc, tx);
+            break;
 
 #ifdef HAVE_NFT_SUPPORT
-                case INS_PROVIDE_NFT_INFORMATION:
-                    handleProvideNFTInformation(G_io_apdu_buffer[OFFSET_P1],
-                                                G_io_apdu_buffer[OFFSET_P2],
-                                                G_io_apdu_buffer + OFFSET_CDATA,
-                                                G_io_apdu_buffer[OFFSET_LC],
-                                                flags,
-                                                tx);
-                    break;
+        case INS_PROVIDE_NFT_INFORMATION:
+            sw = handleProvideNFTInformation(cmd->data, cmd->lc, tx);
+            break;
 #endif  // HAVE_NFT_SUPPORT
 
-                case INS_SET_EXTERNAL_PLUGIN:
-                    handleSetExternalPlugin(G_io_apdu_buffer[OFFSET_P1],
-                                            G_io_apdu_buffer[OFFSET_P2],
-                                            G_io_apdu_buffer + OFFSET_CDATA,
-                                            G_io_apdu_buffer[OFFSET_LC],
-                                            flags,
-                                            tx);
-                    break;
+        case INS_SET_EXTERNAL_PLUGIN:
+            sw = handleSetExternalPlugin(cmd->data, cmd->lc);
+            break;
 
-                case INS_SET_PLUGIN:
-                    handleSetPlugin(G_io_apdu_buffer[OFFSET_P1],
-                                    G_io_apdu_buffer[OFFSET_P2],
-                                    G_io_apdu_buffer + OFFSET_CDATA,
-                                    G_io_apdu_buffer[OFFSET_LC],
-                                    flags,
-                                    tx);
-                    break;
+        case INS_SET_PLUGIN:
+            sw = handleSetPlugin(cmd->data, cmd->lc);
+            break;
 
-                case INS_PERFORM_PRIVACY_OPERATION:
-                    handlePerformPrivacyOperation(G_io_apdu_buffer[OFFSET_P1],
-                                                  G_io_apdu_buffer[OFFSET_P2],
-                                                  G_io_apdu_buffer + OFFSET_CDATA,
-                                                  G_io_apdu_buffer[OFFSET_LC],
-                                                  flags,
-                                                  tx);
-                    break;
+        case INS_PERFORM_PRIVACY_OPERATION:
+            sw = handlePerformPrivacyOperation(cmd->p1, cmd->p2, cmd->data, cmd->lc, flags, tx);
+            break;
 
-                case INS_SIGN:
-                    handleSign(G_io_apdu_buffer[OFFSET_P1],
-                               G_io_apdu_buffer[OFFSET_P2],
-                               G_io_apdu_buffer + OFFSET_CDATA,
-                               G_io_apdu_buffer[OFFSET_LC],
-                               flags,
-                               tx);
-                    break;
+        case INS_SIGN:
+            sw = handleSign(cmd->p1, cmd->p2, cmd->data, cmd->lc, flags);
+            break;
 
-                case INS_GET_APP_CONFIGURATION:
-                    handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1],
-                                              G_io_apdu_buffer[OFFSET_P2],
-                                              G_io_apdu_buffer + OFFSET_CDATA,
-                                              G_io_apdu_buffer[OFFSET_LC],
-                                              flags,
-                                              tx);
-                    break;
+        case INS_GET_APP_CONFIGURATION:
+            sw = handleGetAppConfiguration(tx);
+            break;
 
-                case INS_SIGN_PERSONAL_MESSAGE:
+        case INS_SIGN_PERSONAL_MESSAGE:
+            forget_known_assets();
+            sw = handleSignPersonalMessage(cmd->p1, cmd->data, cmd->lc, flags);
+            break;
+
+        case INS_SIGN_EIP_712_MESSAGE:
+            switch (cmd->p2) {
+                case P2_EIP712_LEGACY_IMPLEM:
                     forget_known_assets();
-                    *flags |= IO_ASYNCH_REPLY;
-                    if (!handleSignPersonalMessage(G_io_apdu_buffer[OFFSET_P1],
-                                                   G_io_apdu_buffer[OFFSET_P2],
-                                                   G_io_apdu_buffer + OFFSET_CDATA,
-                                                   G_io_apdu_buffer[OFFSET_LC])) {
-                        reset_app_context();
-                    }
+                    sw = handleSignEIP712Message_v0(cmd->p1, cmd->data, cmd->lc, flags);
                     break;
-
-                case INS_SIGN_EIP_712_MESSAGE:
-                    switch (G_io_apdu_buffer[OFFSET_P2]) {
-                        case P2_EIP712_LEGACY_IMPLEM:
-                            forget_known_assets();
-                            handleSignEIP712Message_v0(G_io_apdu_buffer[OFFSET_P1],
-                                                       G_io_apdu_buffer[OFFSET_P2],
-                                                       G_io_apdu_buffer + OFFSET_CDATA,
-                                                       G_io_apdu_buffer[OFFSET_LC],
-                                                       flags,
-                                                       tx);
-                            break;
 #ifdef HAVE_EIP712_FULL_SUPPORT
-                        case P2_EIP712_FULL_IMPLEM:
-                            *flags |= IO_ASYNCH_REPLY;
-                            handle_eip712_sign(G_io_apdu_buffer);
-                            break;
-#endif  // HAVE_EIP712_FULL_SUPPORT
-                        default:
-                            THROW(APDU_RESPONSE_INVALID_P1_P2);
-                    }
+                case P2_EIP712_FULL_IMPLEM:
+                    sw = handle_eip712_sign(cmd->data, cmd->lc, flags);
                     break;
+#endif  // HAVE_EIP712_FULL_SUPPORT
+                default:
+                    sw = APDU_RESPONSE_INVALID_P1_P2;
+            }
+            break;
 
 #ifdef HAVE_ETH2
 
-                case INS_GET_ETH2_PUBLIC_KEY:
-                    forget_known_assets();
-                    handleGetEth2PublicKey(G_io_apdu_buffer[OFFSET_P1],
-                                           G_io_apdu_buffer[OFFSET_P2],
-                                           G_io_apdu_buffer + OFFSET_CDATA,
-                                           G_io_apdu_buffer[OFFSET_LC],
-                                           flags,
-                                           tx);
-                    break;
+        case INS_GET_ETH2_PUBLIC_KEY:
+            forget_known_assets();
+            sw = handleGetEth2PublicKey(cmd->p1, cmd->p2, cmd->data, cmd->lc, flags, tx);
+            break;
 
-                case INS_SET_ETH2_WITHDRAWAL_INDEX:
-                    handleSetEth2WithdrawalIndex(G_io_apdu_buffer[OFFSET_P1],
-                                                 G_io_apdu_buffer[OFFSET_P2],
-                                                 G_io_apdu_buffer + OFFSET_CDATA,
-                                                 G_io_apdu_buffer[OFFSET_LC],
-                                                 flags,
-                                                 tx);
-                    break;
+        case INS_SET_ETH2_WITHDRAWAL_INDEX:
+            sw = handleSetEth2WithdrawalIndex(cmd->p1, cmd->p2, cmd->data, cmd->lc);
+            break;
 
 #endif
 
 #ifdef HAVE_EIP712_FULL_SUPPORT
-                case INS_EIP712_STRUCT_DEF:
-                    *flags |= IO_ASYNCH_REPLY;
-                    handle_eip712_struct_def(G_io_apdu_buffer);
-                    break;
+        case INS_EIP712_STRUCT_DEF:
+            sw = handle_eip712_struct_def(cmd->p2, cmd->data, cmd->lc);
+            break;
 
-                case INS_EIP712_STRUCT_IMPL:
-                    *flags |= IO_ASYNCH_REPLY;
-                    handle_eip712_struct_impl(G_io_apdu_buffer);
-                    break;
+        case INS_EIP712_STRUCT_IMPL:
+            sw = handle_eip712_struct_impl(cmd->p1, cmd->p2, cmd->data, cmd->lc, flags);
+            break;
 
-                case INS_EIP712_FILTERING:
-                    *flags |= IO_ASYNCH_REPLY;
-                    handle_eip712_filtering(G_io_apdu_buffer);
-                    break;
+        case INS_EIP712_FILTERING:
+            sw = handle_eip712_filtering(cmd->p1, cmd->p2, cmd->data, cmd->lc, flags);
+            break;
 #endif  // HAVE_EIP712_FULL_SUPPORT
 
-#ifdef HAVE_DOMAIN_NAME
-                case INS_ENS_GET_CHALLENGE:
-                    handle_get_challenge();
-                    break;
-
-                case INS_ENS_PROVIDE_INFO:
-                    handle_provide_domain_name(G_io_apdu_buffer[OFFSET_P1],
-                                               G_io_apdu_buffer[OFFSET_P2],
-                                               G_io_apdu_buffer + OFFSET_CDATA,
-                                               G_io_apdu_buffer[OFFSET_LC]);
-                    break;
-#endif  // HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
+        case INS_ENS_GET_CHALLENGE:
+            sw = handle_get_challenge(tx);
+            break;
 
-#if 0
-        case 0xFF: // return to dashboard
-          goto return_to_dashboard;
-#endif
+        case INS_ENS_PROVIDE_INFO:
+            sw = handle_provide_trusted_name(cmd->p1, cmd->data, cmd->lc);
+            break;
+#endif  // HAVE_TRUSTED_NAME
 
-                default:
-                    THROW(0x6D00);
-                    break;
-            }
-        }
-        CATCH(EXCEPTION_IO_RESET) {
-            THROW(EXCEPTION_IO_RESET);
-        }
-        CATCH_OTHER(e) {
-            bool quit_now = G_called_from_swap && G_swap_response_ready;
-            switch (e & 0xF000) {
-                case 0x6000:
-                    // Wipe the transaction context and report the exception
-                    sw = e;
-                    reset_app_context();
-                    break;
-                case 0x9000:
-                    // All is well
-                    sw = e;
-                    break;
-                default:
-                    // Internal error
-                    sw = 0x6800 | (e & 0x7FF);
-                    reset_app_context();
-                    break;
-            }
-            // Unexpected exception => report
-            G_io_apdu_buffer[*tx] = sw >> 8;
-            G_io_apdu_buffer[*tx + 1] = sw;
-            *tx += 2;
-
-            // If we are in swap mode and have validated a TX, we send it and immediately quit
-            if (quit_now) {
-                if (io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, *tx) == 0) {
-                    // In case of success, the apdu is sent immediately and eth exits
-                    // Reaching this code means we encountered an error
-                    finalize_exchange_sign_transaction(false);
-                } else {
-                    PRINTF("Unrecoverable\n");
-                    os_sched_exit(-1);
-                }
-            }
-        }
-        FINALLY {
-        }
+        default:
+            sw = APDU_RESPONSE_INVALID_INS;
+            break;
     }
-    END_TRY;
+    return sw;
 }
 
 void app_main(void) {
-    unsigned int rx = 0;
-    unsigned int tx = 0;
-    unsigned int flags = 0;
+    uint32_t rx = 0;
+    uint32_t tx = 0;
+    uint32_t flags = 0;
+    uint16_t sw = APDU_NO_RESPONSE;
+    bool quit_now = false;
+    command_t cmd = {0};
 
     // DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only
     // goal is to retrieve APDU.
@@ -382,136 +250,92 @@ void app_main(void) {
     // switch event, before the apdu is replied to the bootloader. This avoid
     // APDU injection faults.
     for (;;) {
-        unsigned short sw = 0;
-
         BEGIN_TRY {
             TRY {
-                rx = tx;
-                tx = 0;  // ensure no race in catch_other if io_exchange throws
-                         // an error
-                rx = io_exchange(CHANNEL_APDU | flags, rx);
-                flags = 0;
-
-                // no apdu received, well, reset the session, and reset the
-                // bootloader configuration
-                if (rx == 0) {
-                    THROW(ERR_APDU_EMPTY);
-                }
-                if (rx > OFFSET_LC && rx != (G_io_apdu_buffer[OFFSET_LC] + 5)) {
-                    THROW(ERR_APDU_SIZE_MISMATCH);
-                }
+                rx = io_exchange(CHANNEL_APDU | flags, tx);
 
-                handleApdu(&flags, &tx);
+                if (apdu_parser(&cmd, G_io_apdu_buffer, rx) == false) {
+                    PRINTF("=> BAD LENGTH: %d\n", rx);
+                    sw = APDU_RESPONSE_WRONG_DATA_LENGTH;
+                } else {
+                    PRINTF("=> CLA=%02x, INS=%02x, P1=%02x, P2=%02x, LC=%02x, CDATA=%.*h\n",
+                           cmd.cla,
+                           cmd.ins,
+                           cmd.p1,
+                           cmd.p2,
+                           cmd.lc,
+                           cmd.lc,
+                           cmd.data);
+
+                    tx = 0;
+                    flags = 0;
+                    sw = handleApdu(&cmd, &flags, &tx);
+                }
             }
             CATCH(EXCEPTION_IO_RESET) {
-                THROW(EXCEPTION_IO_RESET);
+                // reset IO and UX before continuing
+                CLOSE_TRY;
+                app_exit();
             }
             CATCH_OTHER(e) {
-                switch (e & 0xF000) {
-                    case 0x6000:
-                        // Wipe the transaction context and report the exception
-                        sw = e;
-                        reset_app_context();
-                        break;
-                    case 0x9000:
-                        // All is well
-                        sw = e;
-                        break;
-                    default:
-                        // Internal error
-                        sw = 0x6800 | (e & 0x7FF);
-                        reset_app_context();
-                        break;
-                }
-                if (e != 0x9000) {
-                    flags &= ~IO_ASYNCH_REPLY;
-                }
-                // Unexpected exception => report
-                G_io_apdu_buffer[tx] = sw >> 8;
-                G_io_apdu_buffer[tx + 1] = sw;
-                tx += 2;
+                PRINTF("=> CATCH_OTHER: 0x%x\n", e);
+                // Just report the exception
+                sw = e;
             }
             FINALLY {
             }
         }
         END_TRY;
-    }
-}
-
-// override point, but nothing more to do
-#ifdef HAVE_BAGL
-void io_seproxyhal_display(const bagl_element_t *element) {
-    io_seproxyhal_display_default(element);
-}
-#endif
-
-unsigned char io_event(__attribute__((unused)) unsigned char channel) {
-    // nothing done with the event, throw an error on the transport layer if
-    // needed
-
-    // can't have more than one tag in the reply, not supported yet.
-    switch (G_io_seproxyhal_spi_buffer[0]) {
-        case SEPROXYHAL_TAG_FINGER_EVENT:
-            UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
-            break;
-#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 &&
-                !(U4BE(G_io_seproxyhal_spi_buffer, 3) &
-                  SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
-                THROW(EXCEPTION_IO_RESET);
+        if (sw == APDU_NO_RESPONSE) {
+            // Nothing to report
+            continue;
+        }
+        quit_now = G_called_from_swap && G_swap_response_ready;
+        if ((sw != APDU_RESPONSE_OK) && (sw != APDU_RESPONSE_CMD_CODE_NOT_SUPPORTED)) {
+            if ((sw & 0xF000) != 0x6000) {
+                // Internal error
+                sw = APDU_RESPONSE_INTERNAL_ERROR | (sw & 0x7FF);
             }
-            __attribute__((fallthrough));
-        default:
-            UX_DEFAULT_EVENT();
-            break;
+            reset_app_context();
+            flags &= ~IO_ASYNCH_REPLY;
+        }
 
-        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;
+        // Report Status Word
+        U2BE_ENCODE(G_io_apdu_buffer, tx, sw);
+        tx += 2;
 
-        case SEPROXYHAL_TAG_TICKER_EVENT:
-            UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {});
-            break;
-    }
-
-    // close the event if not done previously (by a display or whatever)
-    if (!io_seproxyhal_spi_is_status_sent()) {
-        io_seproxyhal_general_status();
+        // If we are in swap mode and have validated a TX, we send it and immediately quit
+        if (quit_now) {
+            if (io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx) == 0) {
+                // In case of success, the apdu is sent immediately and eth exits
+                // Reaching this code means we encountered an error
+                finalize_exchange_sign_transaction(false);
+            } else {
+                PRINTF("Unrecoverable\n");
+                app_exit();
+            }
+        }
     }
+}
 
-    // command has been processed, DO NOT reset the current APDU transport
-    return 1;
+static void init_coin_config(chain_config_t *coin_config) {
+    memset(coin_config, 0, sizeof(chain_config_t));
+    strcpy(coin_config->coinName, APP_TICKER);
+    coin_config->chainId = APP_CHAIN_ID;
 }
 
-void app_exit() {
-    BEGIN_TRY_L(exit) {
-        TRY_L(exit) {
-            os_sched_exit(-1);
-        }
-        FINALLY_L(exit) {
-        }
+void storage_init(void) {
+    internalStorage_t storage;
+    if (N_storage.initialized) {
+        return;
     }
-    END_TRY_L(exit);
-}
 
-void init_coin_config(chain_config_t *coin_config) {
-    memset(coin_config, 0, sizeof(chain_config_t));
-    strcpy(coin_config->coinName, CHAINID_COINNAME);
-    coin_config->chainId = CHAIN_ID;
+    explicit_bzero(&storage, sizeof(storage));
+    storage.initialized = true;
+    nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t));
 }
 
-__attribute__((noreturn)) void coin_main(libargs_t *args) {
+void coin_main(eth_libargs_t *args) {
     chain_config_t config;
     if (args) {
         if (args->chain_config != NULL) {
@@ -533,61 +357,21 @@ __attribute__((noreturn)) void coin_main(libargs_t *args) {
     }
 
     reset_app_context();
+    storage_init();
+    common_app_init();
 
-    for (;;) {
-        UX_INIT();
+    io_init();
+    ui_idle();
 
-        BEGIN_TRY {
-            TRY {
-                io_seproxyhal_init();
-
-#ifdef HAVE_BLE
-                // grab the current plane mode setting
-                G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
-#endif  // HAVE_BLE
-
-                if (!N_storage.initialized) {
-                    internalStorage_t storage;
-                    explicit_bzero(&storage, sizeof(storage));
-                    storage.initialized = true;
-                    nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t));
-                }
-
-                USB_power(0);
-                USB_power(1);
-
-                ui_idle();
-
-#ifdef HAVE_BLE
-                BLE_power(0, NULL);
-                BLE_power(1, NULL);
-#endif  // HAVE_BLE
-
-#ifdef HAVE_DOMAIN_NAME
-                // to prevent it from having a fixed value at boot
-                roll_challenge();
-#endif  // HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
+    // to prevent it from having a fixed value at boot
+    roll_challenge();
+#endif  // HAVE_TRUSTED_NAME
 
-                app_main();
-            }
-            CATCH(EXCEPTION_IO_RESET) {
-                // reset IO and UX before continuing
-                CLOSE_TRY;
-                continue;
-            }
-            CATCH_ALL {
-                CLOSE_TRY;
-                break;
-            }
-            FINALLY {
-            }
-        }
-        END_TRY;
-    }
-    os_sched_exit(-1);
+    app_main();
 }
 
-__attribute__((noreturn)) void library_main(libargs_t *args) {
+__attribute__((noreturn)) void library_main(eth_libargs_t *args) {
     chain_config_t coin_config;
     if (args->chain_config == NULL) {
         // We have been started directly by Exchange, not by a Clone. Init default chain
@@ -598,7 +382,10 @@ __attribute__((noreturn)) void library_main(libargs_t *args) {
     PRINTF("Inside a library \n");
     switch (args->command) {
         case CHECK_ADDRESS:
-            handle_check_address(args->check_address, args->chain_config);
+            if (handle_check_address(args->check_address, args->chain_config) != APDU_RESPONSE_OK) {
+                // Failed, non recoverable
+                app_exit();
+            }
             break;
         case SIGN_TRANSACTION:
             if (copy_transaction_parameters(args->create_transaction, args->chain_config)) {
@@ -606,11 +393,15 @@ __attribute__((noreturn)) void library_main(libargs_t *args) {
                 handle_swap_sign_transaction(args->chain_config);
             } else {
                 // Failed to copy, non recoverable
-                os_sched_exit(-1);
+                app_exit();
             }
             break;
         case GET_PRINTABLE_AMOUNT:
-            handle_get_printable_amount(args->get_printable_amount, args->chain_config);
+            if (handle_get_printable_amount(args->get_printable_amount, args->chain_config) !=
+                APDU_RESPONSE_OK) {
+                // Failed, non recoverable
+                app_exit();
+            }
             break;
         default:
             break;
@@ -621,62 +412,55 @@ __attribute__((noreturn)) void library_main(libargs_t *args) {
 /* Eth clones do not actually contain any logic, they delegate everything to the ETH application.
  * Start Eth in lib mode with the correct chain config
  */
-__attribute__((noreturn)) void clone_main(libargs_t *args) {
+__attribute__((noreturn)) void clone_main(eth_libargs_t *args) {
     PRINTF("Starting in clone_main\n");
-    BEGIN_TRY {
-        TRY {
-            unsigned int libcall_params[5];
-            chain_config_t local_chainConfig;
-            init_coin_config(&local_chainConfig);
-
-            libcall_params[0] = (unsigned int) "Ethereum";
-            libcall_params[1] = 0x100;
-            libcall_params[3] = (unsigned int) &local_chainConfig;
-
-            // Clone called by Exchange, forward the request to Ethereum
-            if (args != NULL) {
-                if (args->id != 0x100) {
-                    os_sched_exit(0);
-                }
-                libcall_params[2] = args->command;
-                libcall_params[4] = (unsigned int) args->get_printable_amount;
-                os_lib_call((unsigned int *) &libcall_params);
-                // Ethereum fulfilled the request and returned to us. We return to Exchange.
-                os_lib_end();
-            } else {
-                // Clone called from Dashboard, start Ethereum
-                libcall_params[2] = RUN_APPLICATION;
+    uint32_t libcall_params[5];
+    chain_config_t local_chainConfig;
+    init_coin_config(&local_chainConfig);
+
+    libcall_params[0] = (uint32_t) "Ethereum";
+    libcall_params[1] = 0x100;
+    libcall_params[3] = (uint32_t) &local_chainConfig;
+
+    // Clone called by Exchange, forward the request to Ethereum
+    if (args != NULL) {
+        if (args->id != 0x100) {
+            os_sched_exit(0);
+        }
+        libcall_params[2] = args->command;
+        libcall_params[4] = (uint32_t) args->get_printable_amount;
+        os_lib_call((uint32_t *) &libcall_params);
+        // Ethereum fulfilled the request and returned to us. We return to Exchange.
+        os_lib_end();
+    } else {
+        // Clone called from Dashboard, start Ethereum
+        libcall_params[2] = RUN_APPLICATION;
 // On Stax, forward our icon to Ethereum
 #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;
+        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] = (uint32_t) &capp;
 #else
-                libcall_params[4] = 0;
+        libcall_params[4] = 0;
 #endif  // HAVE_NBGL
-                os_lib_call((unsigned int *) &libcall_params);
-                // Ethereum should not return to us
-                os_sched_exit(-1);
-            }
-        }
-        FINALLY {
-        }
+        os_lib_call((uint32_t *) &libcall_params);
+        // Ethereum should not return to us
+        app_exit();
     }
-    END_TRY;
 
     // os_lib_call will raise if Ethereum application is not installed. Do not try to recover.
     os_sched_exit(-1);
 }
 
-int ethereum_main(libargs_t *args) {
+int ethereum_main(eth_libargs_t *args) {
     // exit critical section
     __asm volatile("cpsie i");
 
@@ -707,8 +491,8 @@ int ethereum_main(libargs_t *args) {
 
 __attribute__((section(".boot"))) int main(int arg0) {
 #ifdef USE_LIB_ETHEREUM
-    clone_main((libargs_t *) arg0);
+    clone_main((eth_libargs_t *) arg0);
 #else
-    return ethereum_main((libargs_t *) arg0);
+    return ethereum_main((eth_libargs_t *) arg0);
 #endif
 }
diff --git a/src/network.c b/src/network.c
index 276759564..d9ccd6617 100644
--- a/src/network.c
+++ b/src/network.c
@@ -29,7 +29,7 @@ static const network_info_t NETWORK_MAPPING[] = {
     {.chain_id = 40, .name = "Telos EVM Mainnet", .ticker = "TLOS"},
     {.chain_id = 42, .name = "LUKSO", .ticker = "LYX"},
     {.chain_id = 50, .name = "XDC", .ticker = "XDC"},
-    {.chain_id = 51, .name = "Apothemnetwork", .ticker = "XDC"},
+    {.chain_id = 51, .name = "Apothemnetwork", .ticker = "TXDC"},
     {.chain_id = 56, .name = "BSC", .ticker = "BNB"},
     {.chain_id = 57, .name = "Syscoin", .ticker = "SYS"},
     {.chain_id = 61, .name = "Ethereum Classic", .ticker = "ETC"},
@@ -52,6 +52,7 @@ static const network_info_t NETWORK_MAPPING[] = {
     {.chain_id = 369, .name = "PulseChain", .ticker = "PLS"},
     {.chain_id = 592, .name = "Astar", .ticker = "ASTR"},
     {.chain_id = 888, .name = "Wanchain", .ticker = "WAN"},
+    {.chain_id = 943, .name = "PulseChain Testnet", .ticker = "tPLS"},
     {.chain_id = 1030, .name = "Conflux", .ticker = "CFX"},
     {.chain_id = 1088, .name = "Metis Andromeda", .ticker = "METIS"},
     {.chain_id = 1101, .name = "Polygon zkEVM", .ticker = "ETH"},
diff --git a/src/plugins.c b/src/plugins.c
index ee5a2f77c..3271f3d90 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -1,5 +1,6 @@
 #include "eth_plugin_handler.h"
 #include "ui_callbacks.h"
+#include "common_ui.h"
 
 void plugin_ui_get_id(void) {
     ethQueryContractID_t pluginQueryContractID;
@@ -11,7 +12,8 @@ void plugin_ui_get_id(void) {
     // Query the original contract for ID if it's not an internal alias
     if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_ID, (void *) &pluginQueryContractID)) {
         PRINTF("Plugin query contract ID call failed\n");
-        io_seproxyhal_touch_tx_cancel(NULL);
+        ui_idle();
+        io_seproxyhal_touch_tx_cancel();
     }
 }
 
@@ -28,7 +30,8 @@ void plugin_ui_get_item_internal(char *title_buffer,
                                          msg_buffer_size);
     if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_UI, (void *) &pluginQueryContractUI)) {
         PRINTF("Plugin query contract UI call failed\n");
-        io_seproxyhal_touch_tx_cancel(NULL);
+        ui_idle();
+        io_seproxyhal_touch_tx_cancel();
     }
 }
 
diff --git a/src/public_keys.h b/src/public_keys.h
index d5964dbf4..250d7dfa1 100644
--- a/src/public_keys.h
+++ b/src/public_keys.h
@@ -16,6 +16,7 @@
  ********************************************************************************/
 
 #pragma once
+#include <stdint.h>
 
 static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
 #if defined(HAVE_CAL_TEST_KEY)
@@ -63,8 +64,9 @@ static const uint8_t LEDGER_NFT_METADATA_PUBLIC_KEY[] = {
 #endif
 };
 
-static const uint8_t DOMAIN_NAME_PUB_KEY[] = {
-#ifdef HAVE_DOMAIN_NAME_TEST_KEY
+#ifdef HAVE_TRUSTED_NAME
+static const uint8_t TRUSTED_NAME_PUB_KEY[] = {
+#ifdef HAVE_TRUSTED_NAME_TEST_KEY
     0x04, 0xb9, 0x1f, 0xbe, 0xc1, 0x73, 0xe3, 0xba, 0x4a, 0x71, 0x4e, 0x01, 0x4e, 0xbc,
     0x82, 0x7b, 0x6f, 0x89, 0x9a, 0x9f, 0xa7, 0xf4, 0xac, 0x76, 0x9c, 0xde, 0x28, 0x43,
     0x17, 0xa0, 0x0f, 0x4f, 0x65, 0x0f, 0x09, 0xf0, 0x9a, 0xa4, 0xff, 0x5a, 0x31, 0x76,
@@ -78,6 +80,7 @@ static const uint8_t DOMAIN_NAME_PUB_KEY[] = {
     0xae, 0xf5, 0xaf, 0xcf, 0x90, 0xe8, 0x40, 0x88, 0x71
 #endif
 };
+#endif  // HAVE_TRUSTED_NAME
 
 // Only used for signing NFT plugins (ERC721 and ERC1155)
 static const uint8_t LEDGER_NFT_SELECTOR_PUBLIC_KEY[] = {
@@ -101,3 +104,14 @@ static const uint8_t LEDGER_NFT_SELECTOR_PUBLIC_KEY[] = {
     0x92, 0xc7, 0xc6, 0x48, 0x0d, 0x39, 0xce, 0xbb, 0xa3
 #endif
 };
+
+extern int check_signature_with_pubkey(const char *tag,
+                                       uint8_t *buffer,
+                                       const uint8_t bufLen,
+                                       const uint8_t *PubKey,
+                                       const uint8_t keyLen,
+#ifdef HAVE_LEDGER_PKI
+                                       const uint8_t keyUsageExp,
+#endif
+                                       uint8_t *signature,
+                                       const uint8_t sigLen);
diff --git a/src/shared_context.h b/src/shared_context.h
index dfde37f12..d0fed95d7 100644
--- a/src/shared_context.h
+++ b/src/shared_context.h
@@ -6,6 +6,8 @@
 
 #include "os.h"
 #include "cx.h"
+#include "bip32.h"
+#include "bip32_utils.h"
 #include "ethUstream.h"
 #include "tx_content.h"
 #include "chainConfig.h"
@@ -14,7 +16,8 @@
 #include "nbgl_types.h"
 #endif
 
-#define MAX_BIP32_PATH 10
+extern void app_exit();
+extern void common_app_init(void);
 
 #define SELECTOR_LENGTH 4
 
@@ -24,11 +27,6 @@
 
 #define MAX_ASSETS 5
 
-typedef struct bip32_path_t {
-    uint8_t length;
-    uint32_t path[MAX_BIP32_PATH];
-} bip32_path_t;
-
 typedef struct internalStorage_t {
     bool dataAllowed;
     bool contractDetails;
@@ -36,9 +34,9 @@ typedef struct internalStorage_t {
 #ifdef HAVE_EIP712_FULL_SUPPORT
     bool verbose_eip712;
 #endif  // HAVE_EIP712_FULL_SUPPORT
-#ifdef HAVE_DOMAIN_NAME
-    bool verbose_domain_name;
-#endif  // HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
+    bool verbose_trusted_name;
+#endif  // HAVE_TRUSTED_NAME
     bool initialized;
 } internalStorage_t;
 
@@ -166,14 +164,30 @@ extern strings_t strings;
 extern cx_sha3_t global_sha3;
 extern const internalStorage_t N_storage_real;
 
+typedef enum swap_mode_e {
+    SWAP_MODE_STANDARD,
+    SWAP_MODE_CROSSCHAIN_PENDING_CHECK,
+    SWAP_MODE_CROSSCHAIN_SUCCESS,
+    SWAP_MODE_ERROR,
+} swap_mode_t;
+
 extern bool G_called_from_swap;
 extern bool G_swap_response_ready;
+extern swap_mode_t G_swap_mode;
+extern uint8_t G_swap_crosschain_hash[CX_SHA256_SIZE];
 
 typedef enum {
-    EXTERNAL,     //  External plugin, set by setExternalPlugin.
-    ERC721,       // Specific ERC721 internal plugin, set by setPlugin.
-    ERC1155,      // Specific ERC1155 internal plugin, set by setPlugin
-    OLD_INTERNAL  // Old internal plugin, not set by any command.
+    // External plugin, set by setExternalPlugin
+    EXTERNAL,
+    // Specific SWAP_WITH_CALLDATA internal plugin
+    // set as fallback when started if calldata is provided in swap mode
+    SWAP_WITH_CALLDATA,
+    // Specific ERC721 internal plugin, set by setPlugin
+    ERC721,
+    // Specific ERC1155 internal plugin, set by setPlugin
+    ERC1155,
+    // Old internal plugin, not set by any command
+    OLD_INTERNAL
 } pluginType_t;
 
 extern pluginType_t pluginType;
@@ -185,5 +199,6 @@ extern uint32_t eth2WithdrawalIndex;
 
 void reset_app_context(void);
 const uint8_t *parseBip32(const uint8_t *dataBuffer, uint8_t *dataLength, bip32_path_t *bip32);
+void storage_init(void);
 
 #endif  // _SHARED_CONTEXT_H_
diff --git a/src/swap_lib_calls.h b/src/swap_lib_calls.h
deleted file mode 100644
index c4675e303..000000000
--- a/src/swap_lib_calls.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#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"
-#include "caller_api.h"
-
-#define RUN_APPLICATION 1
-
-#define SIGN_TRANSACTION 2
-
-#define CHECK_ADDRESS 3
-
-#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
-    uint8_t *coin_configuration;
-    uint8_t coin_configuration_length;
-    // serialized path, segwit, version prefix, hash used, dictionary etc.
-    // 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;
-
-// structure that should be send to specific coin application to get printable amount
-typedef struct get_printable_amount_parameters_s {
-    // IN
-    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];
-} get_printable_amount_parameters_t;
-
-typedef struct create_transaction_parameters_s {
-    // 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;
-
-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/ui_callbacks.h b/src/ui_callbacks.h
index bd933c471..52296356f 100644
--- a/src/ui_callbacks.h
+++ b/src/ui_callbacks.h
@@ -7,18 +7,19 @@
 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);
-unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e);
-unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e);
-unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e);
+unsigned int io_seproxyhal_touch_tx_ok(void);
+unsigned int io_seproxyhal_touch_tx_cancel(void);
+unsigned int io_seproxyhal_touch_address_ok(void);
+unsigned int io_seproxyhal_touch_address_cancel(void);
 unsigned int io_seproxyhal_touch_signMessage_ok(void);
 unsigned int io_seproxyhal_touch_signMessage_cancel(void);
-unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e);
-unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e);
-unsigned int io_seproxyhal_touch_eth2_address_ok(const bagl_element_t *e);
-unsigned int io_seproxyhal_touch_privacy_ok(const bagl_element_t *e);
-unsigned int io_seproxyhal_touch_privacy_cancel(const bagl_element_t *e);
+unsigned int io_seproxyhal_touch_data_ok(void);
+unsigned int io_seproxyhal_touch_data_cancel(void);
+unsigned int io_seproxyhal_touch_eth2_address_ok(void);
+unsigned int io_seproxyhal_touch_privacy_ok(void);
+unsigned int io_seproxyhal_touch_privacy_cancel(void);
+unsigned int address_cancel_cb(void);
+unsigned int tx_ok_cb(void);
+unsigned int tx_cancel_cb(void);
 
-void io_seproxyhal_send_status(uint32_t sw);
+uint16_t io_seproxyhal_send_status(uint16_t sw, uint32_t tx, bool reset, bool idle);
diff --git a/src/uint128.c b/src/uint128.c
index 1dda65046..e25428e20 100644
--- a/src/uint128.c
+++ b/src/uint128.c
@@ -19,13 +19,14 @@
 
 #include <stdio.h>
 #include <string.h>
+#include "read.h"
 #include "uint128.h"
 #include "uint_common.h"
 #include "common_utils.h"  // HEXDIGITS
 
 void readu128BE(const uint8_t *const buffer, uint128_t *const target) {
-    UPPER_P(target) = readUint64BE(buffer);
-    LOWER_P(target) = readUint64BE(buffer + 8);
+    UPPER_P(target) = read_u64_be(buffer, 0);
+    LOWER_P(target) = read_u64_be(buffer + 8, 0);
 }
 
 bool zero128(const uint128_t *const number) {
diff --git a/src/uint256.c b/src/uint256.c
index 7445b426c..2d1d6a320 100644
--- a/src/uint256.c
+++ b/src/uint256.c
@@ -20,6 +20,8 @@
 #include <stdio.h>
 #include <string.h>
 #include "uint256.h"
+#include "read.h"
+#include "write.h"
 #include "uint_common.h"
 #include "common_utils.h"  // INT256_LENGTH
 
@@ -162,19 +164,23 @@ void or256(const uint256_t *const number1,
     or128(&LOWER_P(number1), &LOWER_P(number2), &LOWER_P(target));
 }
 
-void mul256(const uint256_t *const number1,
+bool mul256(const uint256_t *const number1,
             const uint256_t *const number2,
             uint256_t *const target) {
     uint8_t num1[INT256_LENGTH], num2[INT256_LENGTH], result[INT256_LENGTH * 2];
     memset(&result, 0, sizeof(result));
     for (uint8_t i = 0; i < 4; i++) {
-        write_u64_be(num1 + i * sizeof(uint64_t), number1->elements[i / 2].elements[i % 2]);
-        write_u64_be(num2 + i * sizeof(uint64_t), number2->elements[i / 2].elements[i % 2]);
+        write_u64_be(num1 + i * sizeof(uint64_t), 0, number1->elements[i / 2].elements[i % 2]);
+        write_u64_be(num2 + i * sizeof(uint64_t), 0, number2->elements[i / 2].elements[i % 2]);
+    }
+    if (cx_math_mult_no_throw(result, num1, num2, sizeof(num1)) != CX_OK) {
+        return false;
     }
-    CX_ASSERT(cx_math_mult_no_throw(result, num1, num2, sizeof(num1)));
     for (uint8_t i = 0; i < 4; i++) {
-        read_u64_be(result + 32 + i * sizeof(uint64_t), &target->elements[i / 2].elements[i % 2]);
+        target->elements[i / 2].elements[i % 2] =
+            read_u64_be((result + 32 + i * sizeof(uint64_t)), 0);
     }
+    return true;
 }
 
 void divmod256(const uint256_t *const l,
diff --git a/src/uint256.h b/src/uint256.h
index 4addf7f78..6e2a1c614 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -45,7 +45,7 @@ void sub256(const uint256_t *const number1,
             const uint256_t *const number2,
             uint256_t *const target);
 void or256(const uint256_t *const number1, const uint256_t *const number2, uint256_t *const target);
-void mul256(const uint256_t *const number1,
+bool mul256(const uint256_t *const number1,
             const uint256_t *const number2,
             uint256_t *const target);
 void divmod256(const uint256_t *const l,
diff --git a/src/uint_common.c b/src/uint_common.c
index 5fe06a7c4..12264a362 100644
--- a/src/uint_common.c
+++ b/src/uint_common.c
@@ -15,40 +15,8 @@
  *  limitations under the License.
  ********************************************************************************/
 
-// Adapted from https://github.com/calccrypto/uint256_t
-
 #include "uint_common.h"
 
-void write_u64_be(uint8_t *const buffer, uint64_t value) {
-    buffer[0] = ((value >> 56) & 0xff);
-    buffer[1] = ((value >> 48) & 0xff);
-    buffer[2] = ((value >> 40) & 0xff);
-    buffer[3] = ((value >> 32) & 0xff);
-    buffer[4] = ((value >> 24) & 0xff);
-    buffer[5] = ((value >> 16) & 0xff);
-    buffer[6] = ((value >> 8) & 0xff);
-    buffer[7] = (value & 0xff);
-}
-
-void read_u64_be(const uint8_t *const in, uint64_t *const out) {
-    uint8_t *out_ptr = (uint8_t *) out;
-    *out_ptr++ = in[7];
-    *out_ptr++ = in[6];
-    *out_ptr++ = in[5];
-    *out_ptr++ = in[4];
-    *out_ptr++ = in[3];
-    *out_ptr++ = in[2];
-    *out_ptr++ = in[1];
-    *out_ptr = in[0];
-}
-
-uint64_t readUint64BE(const uint8_t *const buffer) {
-    return (((uint64_t) buffer[0]) << 56) | (((uint64_t) buffer[1]) << 48) |
-           (((uint64_t) buffer[2]) << 40) | (((uint64_t) buffer[3]) << 32) |
-           (((uint64_t) buffer[4]) << 24) | (((uint64_t) buffer[5]) << 16) |
-           (((uint64_t) buffer[6]) << 8) | (((uint64_t) buffer[7]));
-}
-
 void reverseString(char *const str, uint32_t length) {
     uint32_t i, j;
     for (i = 0, j = length - 1; i < j; i++, j--) {
diff --git a/src/uint_common.h b/src/uint_common.h
index c0e9ac23c..36ab3c9f9 100644
--- a/src/uint_common.h
+++ b/src/uint_common.h
@@ -15,8 +15,6 @@
  *  limitations under the License.
  ********************************************************************************/
 
-// Adapted from https://github.com/calccrypto/uint256_t
-
 #ifndef _UINT_COMMON_H_
 #define _UINT_COMMON_H_
 
@@ -30,9 +28,6 @@
 #define UPPER(x)   x.elements[0]
 #define LOWER(x)   x.elements[1]
 
-void write_u64_be(uint8_t *const buffer, uint64_t value);
-void read_u64_be(const uint8_t *const in, uint64_t *const out);
-uint64_t readUint64BE(const uint8_t *const buffer);
 void reverseString(char *const str, uint32_t length);
 
 #endif  //_UINT_COMMON_H_
diff --git a/src_bagl/common_ui.c b/src_bagl/common_ui.c
index 80645a360..96826f8e6 100644
--- a/src_bagl/common_ui.c
+++ b/src_bagl/common_ui.c
@@ -49,4 +49,19 @@ void ui_confirm_parameter(void) {
     ux_flow_init(0, ux_confirm_parameter_flow, NULL);
 }
 
+unsigned int address_cancel_cb(void) {
+    ui_idle();
+    return io_seproxyhal_touch_address_cancel();
+}
+
+unsigned int tx_ok_cb(void) {
+    ui_idle();
+    return io_seproxyhal_touch_tx_ok();
+}
+
+unsigned int tx_cancel_cb(void) {
+    ui_idle();
+    return io_seproxyhal_touch_tx_cancel();
+}
+
 #endif  // HAVE_BAGL
diff --git a/src_bagl/ui_domain_name.h b/src_bagl/ui_domain_name.h
deleted file mode 100644
index bcfa8b06d..000000000
--- a/src_bagl/ui_domain_name.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifdef HAVE_DOMAIN_NAME
-
-#ifndef UI_DOMAIN_NAME_H_
-#define UI_DOMAIN_NAME_H_
-
-#include "ux.h"
-
-extern const ux_flow_step_t ux_domain_name_step;
-
-#endif  // UI_DOMAIN_NAME_H_
-
-#endif  // HAVE_DOMAIN_NAME
diff --git a/src_bagl/ui_flow.c b/src_bagl/ui_flow.c
index 53a57ddd0..43a115ef2 100644
--- a/src_bagl/ui_flow.c
+++ b/src_bagl/ui_flow.c
@@ -10,19 +10,19 @@
 
 // Reuse the strings.common.fullAmount buffer for settings displaying.
 // No risk of collision as this buffer is unused in the settings menu
-#define SETTING_BLIND_SIGNING_STATE       (strings.common.fullAmount + (BUF_INCREMENT * 0))
-#define SETTING_VERBOSE_DOMAIN_NAME_STATE (strings.common.fullAmount + (BUF_INCREMENT * 1))
-#define SETTING_DISPLAY_NONCE_STATE       (strings.common.fullAmount + (BUF_INCREMENT * 2))
-#define SETTING_VERBOSE_EIP712_STATE      (strings.common.fullAmount + (BUF_INCREMENT * 3))
-#define SETTING_DISPLAY_DATA_STATE        (strings.common.fullAmount + (BUF_INCREMENT * 4))
+#define SETTING_BLIND_SIGNING_STATE        (strings.common.fullAmount + (BUF_INCREMENT * 0))
+#define SETTING_VERBOSE_TRUSTED_NAME_STATE (strings.common.fullAmount + (BUF_INCREMENT * 1))
+#define SETTING_DISPLAY_NONCE_STATE        (strings.common.fullAmount + (BUF_INCREMENT * 2))
+#define SETTING_VERBOSE_EIP712_STATE       (strings.common.fullAmount + (BUF_INCREMENT * 3))
+#define SETTING_DISPLAY_DATA_STATE         (strings.common.fullAmount + (BUF_INCREMENT * 4))
 
 #define BOOL_TO_STATE_STR(b) (b ? ENABLED_STR : DISABLED_STR)
 
 static void display_settings(const ux_flow_step_t* const start_step);
 static void switch_settings_blind_signing(void);
-#ifdef HAVE_DOMAIN_NAME
-static void switch_settings_verbose_domain_name(void);
-#endif  // HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
+static void switch_settings_verbose_trusted_name(void);
+#endif  // HAVE_TRUSTED_NAME
 static void switch_settings_display_data(void);
 static void switch_settings_display_nonce(void);
 #ifdef HAVE_EIP712_FULL_SUPPORT
@@ -57,7 +57,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_idle_flow_4_step,
     pb,
-    os_sched_exit(-1),
+    app_exit(),
     {
       &C_icon_dashboard_x,
       "Quit",
@@ -92,18 +92,18 @@ UX_STEP_CB(
       SETTING_BLIND_SIGNING_STATE
     });
 
-#ifdef HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
 UX_STEP_CB(
-    ux_settings_flow_verbose_domain_name_step,
+    ux_settings_flow_verbose_trusted_name_step,
     bnnn,
-    switch_settings_verbose_domain_name(),
+    switch_settings_verbose_trusted_name(),
     {
       "ENS addresses",
       "Displays resolved",
       "addresses from ENS",
-      SETTING_VERBOSE_DOMAIN_NAME_STATE
+      SETTING_VERBOSE_TRUSTED_NAME_STATE
     });
-#endif // HAVE_DOMAIN_NAME
+#endif // HAVE_TRUSTED_NAME
 
 UX_STEP_CB(
     ux_settings_flow_display_nonce_step,
@@ -170,9 +170,9 @@ UX_STEP_CB(
 
 UX_FLOW(ux_settings_flow,
         &ux_settings_flow_blind_signing_step,
-#ifdef HAVE_DOMAIN_NAME
-        &ux_settings_flow_verbose_domain_name_step,
-#endif  // HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
+        &ux_settings_flow_verbose_trusted_name_step,
+#endif  // HAVE_TRUSTED_NAME
         &ux_settings_flow_display_nonce_step,
 #ifdef HAVE_EIP712_FULL_SUPPORT
         &ux_settings_flow_verbose_eip712_step,
@@ -191,11 +191,11 @@ static void display_settings(const ux_flow_step_t* const start_step) {
             BOOL_TO_STATE_STR(N_storage.verbose_eip712),
             BUF_INCREMENT);
 #endif  // HAVE_EIP712_FULL_SUPPORT
-#ifdef HAVE_DOMAIN_NAME
-    strlcpy(SETTING_VERBOSE_DOMAIN_NAME_STATE,
-            BOOL_TO_STATE_STR(N_storage.verbose_domain_name),
+#ifdef HAVE_TRUSTED_NAME
+    strlcpy(SETTING_VERBOSE_TRUSTED_NAME_STATE,
+            BOOL_TO_STATE_STR(N_storage.verbose_trusted_name),
             BUF_INCREMENT);
-#endif  // HAVE_DOMAIN_NAME
+#endif  // HAVE_TRUSTED_NAME
 
     ux_flow_init(0, ux_settings_flow, start_step);
 }
@@ -224,11 +224,11 @@ static void switch_settings_verbose_eip712(void) {
 }
 #endif  // HAVE_EIP712_FULL_SUPPORT
 
-#ifdef HAVE_DOMAIN_NAME
-static void switch_settings_verbose_domain_name(void) {
-    toggle_setting(&N_storage.verbose_domain_name, &ux_settings_flow_verbose_domain_name_step);
+#ifdef HAVE_TRUSTED_NAME
+static void switch_settings_verbose_trusted_name(void) {
+    toggle_setting(&N_storage.verbose_trusted_name, &ux_settings_flow_verbose_trusted_name_step);
 }
-#endif  // HAVE_DOMAIN_NAME
+#endif  // HAVE_TRUSTED_NAME
 
 //////////////////////////////////////////////////////////////////////
 // clang-format off
diff --git a/src_bagl/ui_flow.h b/src_bagl/ui_flow.h
index 1bc3074b8..5a040e68c 100644
--- a/src_bagl/ui_flow.h
+++ b/src_bagl/ui_flow.h
@@ -32,4 +32,6 @@ extern const ux_flow_step_t* const ux_display_privacy_shared_secret_flow[];
 
 extern const ux_flow_step_t* ux_approval_tx_flow[15];
 
+extern const ux_flow_step_t ux_warning_blind_signing_warn_step;
+
 #endif  // _UI_FLOW_H_
diff --git a/src_bagl/ui_flow_erc20_approval.c b/src_bagl/ui_flow_erc20_approval.c
index 9c512b40d..28ed3f7bb 100644
--- a/src_bagl/ui_flow_erc20_approval.c
+++ b/src_bagl/ui_flow_erc20_approval.c
@@ -45,7 +45,7 @@ UX_STEP_NOCB(
 UX_STEP_CB(
     ux_approval_allowance_6_step,
     pbb,
-    io_seproxyhal_touch_tx_ok(NULL),
+    tx_ok_cb(),
     {
       &C_icon_validate_14,
       "Accept",
@@ -55,7 +55,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_approval_allowance_7_step,
     pb,
-    io_seproxyhal_touch_tx_cancel(NULL),
+    tx_cancel_cb(),
     {
       &C_icon_crossmark,
       "Reject",
diff --git a/src_bagl/ui_flow_getEth2PublicKey.c b/src_bagl/ui_flow_getEth2PublicKey.c
index cccf070f8..9d2122655 100644
--- a/src_bagl/ui_flow_getEth2PublicKey.c
+++ b/src_bagl/ui_flow_getEth2PublicKey.c
@@ -31,7 +31,7 @@ UX_STEP_NOCB_INIT(
 UX_STEP_CB(
     ux_display_public_eth2_flow_3_step,
     pb,
-    io_seproxyhal_touch_eth2_address_ok(NULL),
+    io_seproxyhal_touch_eth2_address_ok(),
     {
       &C_icon_validate_14,
       "Approve",
@@ -39,7 +39,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_display_public_eth2_flow_4_step,
     pb,
-    io_seproxyhal_touch_address_cancel(NULL),
+    address_cancel_cb(),
     {
       &C_icon_crossmark,
       "Reject",
diff --git a/src_bagl/ui_flow_getPublicKey.c b/src_bagl/ui_flow_getPublicKey.c
index 3ca3f7713..d70396d75 100644
--- a/src_bagl/ui_flow_getPublicKey.c
+++ b/src_bagl/ui_flow_getPublicKey.c
@@ -1,5 +1,11 @@
 #include "shared_context.h"
 #include "ui_callbacks.h"
+#include "common_ui.h"
+
+static unsigned int address_ok_cb(void) {
+    ui_idle();
+    return io_seproxyhal_touch_address_ok();
+}
 
 // clang-format off
 UX_STEP_NOCB(
@@ -20,7 +26,7 @@ UX_STEP_NOCB(
 UX_STEP_CB(
     ux_display_public_flow_3_step,
     pb,
-    io_seproxyhal_touch_address_ok(NULL),
+    address_ok_cb(),
     {
       &C_icon_validate_14,
       "Approve",
@@ -28,7 +34,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_display_public_flow_4_step,
     pb,
-    io_seproxyhal_touch_address_cancel(NULL),
+    address_cancel_cb(),
     {
       &C_icon_crossmark,
       "Reject",
diff --git a/src_bagl/ui_flow_performPrivacyOperation.c b/src_bagl/ui_flow_performPrivacyOperation.c
index d1cb8d362..2fd411fad 100644
--- a/src_bagl/ui_flow_performPrivacyOperation.c
+++ b/src_bagl/ui_flow_performPrivacyOperation.c
@@ -27,7 +27,7 @@ UX_STEP_NOCB(
 UX_STEP_CB(
     ux_display_privacy_public_key_flow_4_step,
     pb,
-    io_seproxyhal_touch_privacy_ok(NULL),
+    io_seproxyhal_touch_privacy_ok(),
     {
       &C_icon_validate_14,
       "Approve",
@@ -35,7 +35,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_display_privacy_public_key_flow_5_step,
     pb,
-    io_seproxyhal_touch_privacy_cancel(NULL),
+    io_seproxyhal_touch_privacy_cancel(),
     {
       &C_icon_crossmark,
       "Reject",
diff --git a/src_bagl/ui_flow_signMessage.c b/src_bagl/ui_flow_signMessage.c
index 60b3fcafb..561bb6cde 100644
--- a/src_bagl/ui_flow_signMessage.c
+++ b/src_bagl/ui_flow_signMessage.c
@@ -28,6 +28,16 @@ static void dummy_post_cb(void) {
     }
 }
 
+static unsigned int signMessage_ok_cb(void) {
+    ui_idle();
+    return io_seproxyhal_touch_signMessage_ok();
+}
+
+static unsigned int signMessage_cancel_cb(void) {
+    ui_idle();
+    return io_seproxyhal_touch_signMessage_cancel();
+}
+
 // clang-format off
 UX_STEP_NOCB(
     ux_191_step_review,
@@ -79,7 +89,7 @@ UX_STEP_INIT(
 UX_STEP_CB(
     ux_191_step_sign,
     pbb,
-    io_seproxyhal_touch_signMessage_ok(),
+    signMessage_ok_cb(),
     {
       &C_icon_validate_14,
       "Sign",
@@ -88,7 +98,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_191_step_cancel,
     pbb,
-    io_seproxyhal_touch_signMessage_cancel(),
+    signMessage_cancel_cb(),
     {
       &C_icon_crossmark,
       "Cancel",
diff --git a/src_bagl/ui_flow_signMessage712.c b/src_bagl/ui_flow_signMessage712.c
index 3ffb5b023..1596abdc0 100644
--- a/src_bagl/ui_flow_signMessage712.c
+++ b/src_bagl/ui_flow_signMessage712.c
@@ -2,9 +2,15 @@
 
 #include "ui_logic.h"
 #include "shared_context.h"  // strings
+#include "common_ui.h"
+#include "ui_flow.h"  // ux_warning_blind_signing_warn_step
 
 enum { UI_712_POS_REVIEW, UI_712_POS_END };
 static uint8_t ui_pos;
+static bool filtered;
+
+// forward declaration for the BAGL step
+static void ui_712_start_flow(void);
 
 static void dummy_cb(void) {
     switch (ui_712_next_field()) {
@@ -28,6 +34,16 @@ static void dummy_cb(void) {
     }
 }
 
+static unsigned int _approve_cb(void) {
+    ui_idle();
+    return ui_712_approve();
+}
+
+static unsigned int _reject_cb(void) {
+    ui_idle();
+    return ui_712_reject();
+}
+
 // clang-format off
 UX_STEP_NOCB(
     ux_712_step_review,
@@ -56,19 +72,37 @@ UX_STEP_INIT(
 UX_STEP_CB(
     ux_712_step_approve,
     pb,
-    ui_712_approve(),
+    _approve_cb(),
     {
       &C_icon_validate_14,
       "Approve",
     });
+UX_STEP_CB(
+    ux_712_step_approve_risky,
+    pbb,
+    _approve_cb(),
+    {
+      &C_icon_validate_14,
+      "Accept risk",
+      "and sign",
+    });
 UX_STEP_CB(
     ux_712_step_reject,
     pb,
-    ui_712_reject(),
+    _reject_cb(),
     {
       &C_icon_crossmark,
       "Reject",
     });
+
+UX_STEP_INIT(
+   ux_712_warning_blind_signing_jump_step,
+   NULL,
+   NULL,
+   {
+     ui_712_start_flow();
+   }
+);
 // clang-format on
 
 UX_FLOW(ux_712_flow,
@@ -78,18 +112,40 @@ UX_FLOW(ux_712_flow,
         &ux_712_step_approve,
         &ux_712_step_reject);
 
-void ui_712_start(void) {
-    ux_flow_init(0, ux_712_flow, NULL);
+UX_FLOW(ux_712_flow_unfiltered,
+        &ux_712_step_review,
+        &ux_712_step_dynamic,
+        &ux_712_step_dummy,
+        &ux_712_step_approve_risky,
+        &ux_712_step_reject);
+
+UX_FLOW(ux_712_warning_blind_signing_flow,
+        &ux_warning_blind_signing_warn_step,
+        &ux_712_warning_blind_signing_jump_step);
+
+static void ui_712_start_flow(void) {
+    ux_flow_init(0, filtered ? ux_712_flow : ux_712_flow_unfiltered, NULL);
     ui_pos = UI_712_POS_REVIEW;
 }
+void ui_712_start(void) {
+    filtered = true;
+    ui_712_start_flow();
+}
+
+void ui_712_start_unfiltered(void) {
+    filtered = false;
+    ux_flow_init(0, ux_712_warning_blind_signing_flow, NULL);
+}
 
 void ui_712_switch_to_message(void) {
-    ux_flow_init(0, ux_712_flow, &ux_712_step_dynamic);
+    ux_flow_init(0, filtered ? ux_712_flow : ux_712_flow_unfiltered, &ux_712_step_dynamic);
     ui_pos = UI_712_POS_REVIEW;
 }
 
 void ui_712_switch_to_sign(void) {
-    ux_flow_init(0, ux_712_flow, &ux_712_step_approve);
+    ux_flow_init(0,
+                 filtered ? ux_712_flow : ux_712_flow_unfiltered,
+                 filtered ? &ux_712_step_approve : &ux_712_step_approve_risky);
     ui_pos = UI_712_POS_END;
 }
 
diff --git a/src_bagl/ui_flow_signMessage712_v0.c b/src_bagl/ui_flow_signMessage712_v0.c
index 72c643509..e6ee1b359 100644
--- a/src_bagl/ui_flow_signMessage712_v0.c
+++ b/src_bagl/ui_flow_signMessage712_v0.c
@@ -2,6 +2,8 @@
 #include "ui_callbacks.h"
 #include "common_712.h"
 #include "uint_common.h"
+#include "common_ui.h"
+#include "ui_flow.h"  // ux_warning_blind_signing_warn_step
 
 void prepare_domain_hash_v0() {
     array_bytes_string(strings.tmp.tmp,
@@ -17,6 +19,16 @@ void prepare_message_hash_v0() {
                        KECCAK256_HASH_BYTESIZE);
 }
 
+static unsigned int _approve_cb(void) {
+    ui_idle();
+    return ui_712_approve_cb();
+}
+
+static unsigned int _reject_cb(void) {
+    ui_idle();
+    return ui_712_reject_cb();
+}
+
 // clang-format off
 UX_STEP_NOCB(
     ux_sign_712_v0_flow_1_step,
@@ -45,16 +57,16 @@ UX_STEP_NOCB_INIT(
 UX_STEP_CB(
     ux_sign_712_v0_flow_4_step,
     pbb,
-    ui_712_approve_cb(),
+    _approve_cb(),
     {
       &C_icon_validate_14,
-      "Sign",
-      "message",
+      "Accept risk",
+      "and sign",
     });
 UX_STEP_CB(
     ux_sign_712_v0_flow_5_step,
     pbb,
-    ui_712_reject_cb(),
+    _reject_cb(),
     {
       &C_icon_crossmark,
       "Cancel",
@@ -63,6 +75,7 @@ UX_STEP_CB(
 // clang-format on
 
 UX_FLOW(ux_sign_712_v0_flow,
+        &ux_warning_blind_signing_warn_step,
         &ux_sign_712_v0_flow_1_step,
         &ux_sign_712_v0_flow_2_step,
         &ux_sign_712_v0_flow_3_step,
diff --git a/src_bagl/ui_flow_signTx.c b/src_bagl/ui_flow_signTx.c
index f854eca7d..6558442e0 100644
--- a/src_bagl/ui_flow_signTx.c
+++ b/src_bagl/ui_flow_signTx.c
@@ -8,8 +8,18 @@
 #include "ui_plugin.h"
 #include "common_ui.h"
 #include "plugins.h"
-#include "domain_name.h"
-#include "ui_domain_name.h"
+#include "trusted_name.h"
+#include "ui_trusted_name.h"
+
+static unsigned int data_ok_cb(void) {
+    ui_idle();
+    return io_seproxyhal_touch_data_ok();
+}
+
+static unsigned int data_cancel_cb(void) {
+    ui_idle();
+    return io_seproxyhal_touch_data_cancel();
+}
 
 // clang-format off
 UX_STEP_NOCB(
@@ -31,7 +41,7 @@ UX_STEP_NOCB(
 UX_STEP_CB(
     ux_confirm_selector_flow_3_step,
     pb,
-    io_seproxyhal_touch_data_ok(NULL),
+    data_ok_cb(),
     {
       &C_icon_validate_14,
       "Approve",
@@ -39,7 +49,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_confirm_selector_flow_4_step,
     pb,
-    io_seproxyhal_touch_data_cancel(NULL),
+    data_cancel_cb(),
     {
       &C_icon_crossmark,
       "Reject",
@@ -72,7 +82,7 @@ UX_STEP_NOCB(
 UX_STEP_CB(
     ux_confirm_parameter_flow_3_step,
     pb,
-    io_seproxyhal_touch_data_ok(NULL),
+    data_ok_cb(),
     {
       &C_icon_validate_14,
       "Approve",
@@ -80,7 +90,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_confirm_parameter_flow_4_step,
     pb,
-    io_seproxyhal_touch_data_cancel(NULL),
+    data_cancel_cb(),
     {
       &C_icon_crossmark,
       "Reject",
@@ -176,7 +186,7 @@ UX_STEP_NOCB(
 UX_STEP_CB(
     ux_approval_accept_step,
     pbb,
-    io_seproxyhal_touch_tx_ok(NULL),
+    tx_ok_cb(),
     {
       &C_icon_validate_14,
       "Accept",
@@ -185,7 +195,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_approval_accept_blind_step,
     pbb,
-    io_seproxyhal_touch_tx_ok(NULL),
+    tx_ok_cb(),
     {
       &C_icon_validate_14,
       "Accept risk",
@@ -194,7 +204,7 @@ UX_STEP_CB(
 UX_STEP_CB(
     ux_approval_reject_step,
     pb,
-    io_seproxyhal_touch_tx_cancel(NULL),
+    tx_cancel_cb(),
     {
       &C_icon_crossmark,
       "Reject",
@@ -232,19 +242,20 @@ void ux_approve_tx(bool fromPlugin) {
             ux_approval_tx_flow[step++] = &ux_approval_from_step;
         }
         ux_approval_tx_flow[step++] = &ux_approval_amount_step;
-#ifdef HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
         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) {
+        e_name_type type = TYPE_ACCOUNT;
+        if (has_trusted_name(1, &type, &chain_id, tmpContent.txContent.destination)) {
+            ux_approval_tx_flow[step++] = &ux_trusted_name_step;
+            if (N_storage.verbose_trusted_name) {
                 ux_approval_tx_flow[step++] = &ux_approval_to_step;
             }
         } else {
-#endif  // HAVE_DOMAIN_NAME
+#endif  // HAVE_TRUSTED_NAME
             ux_approval_tx_flow[step++] = &ux_approval_to_step;
-#ifdef HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
         }
-#endif  // HAVE_DOMAIN_NAME
+#endif  // HAVE_TRUSTED_NAME
     }
 
     if (N_storage.displayNonce) {
diff --git a/src_bagl/ui_domain_name.c b/src_bagl/ui_trusted_name.c
similarity index 53%
rename from src_bagl/ui_domain_name.c
rename to src_bagl/ui_trusted_name.c
index 3807a6132..c756520df 100644
--- a/src_bagl/ui_domain_name.c
+++ b/src_bagl/ui_trusted_name.c
@@ -1,17 +1,17 @@
-#ifdef HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
 
-#include "ui_domain_name.h"
-#include "domain_name.h"
+#include "ui_trusted_name.h"
+#include "trusted_name.h"
 
 //////////////////////////////////////////////////////////////////////
 // clang-format off
 UX_STEP_NOCB(
-    ux_domain_name_step,
+    ux_trusted_name_step,
     bnnn_paging,
     {
       .title = "To (domain)",
-      .text = g_domain_name
+      .text = g_trusted_name
     });
 // clang-format on
 
-#endif  // HAVE_DOMAIN_NAME
+#endif  // HAVE_TRUSTED_NAME
diff --git a/src_bagl/ui_trusted_name.h b/src_bagl/ui_trusted_name.h
new file mode 100644
index 000000000..ac76dcaae
--- /dev/null
+++ b/src_bagl/ui_trusted_name.h
@@ -0,0 +1,12 @@
+#ifdef HAVE_TRUSTED_NAME
+
+#ifndef UI_TRUSTED_NAME_H_
+#define UI_TRUSTED_NAME_H_
+
+#include "ux.h"
+
+extern const ux_flow_step_t ux_trusted_name_step;
+
+#endif  // UI_TRUSTED_NAME_H_
+
+#endif  // HAVE_TRUSTED_NAME
diff --git a/src_features/getAppConfiguration/cmd_getAppConfiguration.c b/src_features/getAppConfiguration/cmd_getAppConfiguration.c
index 8b137d503..761612314 100644
--- a/src_features/getAppConfiguration/cmd_getAppConfiguration.c
+++ b/src_features/getAppConfiguration/cmd_getAppConfiguration.c
@@ -1,22 +1,12 @@
 #include "shared_context.h"
 #include "apdu_constants.h"
 
-void handleGetAppConfiguration(uint8_t p1,
-                               uint8_t p2,
-                               const uint8_t *workBuffer,
-                               uint8_t dataLength,
-                               unsigned int *flags,
-                               unsigned int *tx) {
-    UNUSED(p1);
-    UNUSED(p2);
-    UNUSED(workBuffer);
-    UNUSED(dataLength);
-    UNUSED(flags);
+uint16_t handleGetAppConfiguration(unsigned int *tx) {
     G_io_apdu_buffer[0] = (N_storage.dataAllowed ? APP_FLAG_DATA_ALLOWED : 0x00);
     G_io_apdu_buffer[0] |= APP_FLAG_EXTERNAL_TOKEN_NEEDED;
     G_io_apdu_buffer[1] = MAJOR_VERSION;
     G_io_apdu_buffer[2] = MINOR_VERSION;
     G_io_apdu_buffer[3] = PATCH_VERSION;
     *tx = 4;
-    THROW(0x9000);
+    return APDU_RESPONSE_OK;
 }
diff --git a/src_features/getChallenge/challenge.h b/src_features/getChallenge/challenge.h
index 9fdb01dcf..a671945b4 100644
--- a/src_features/getChallenge/challenge.h
+++ b/src_features/getChallenge/challenge.h
@@ -1,4 +1,4 @@
-#ifdef HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
 
 #ifndef CHALLENGE_H_
 #define CHALLENGE_H_
@@ -7,8 +7,8 @@
 
 void roll_challenge(void);
 uint32_t get_challenge(void);
-void handle_get_challenge(void);
+uint16_t handle_get_challenge(unsigned int *tx);
 
 #endif  // CHALLENGE_H_
 
-#endif  // HAVE_DOMAIN_NAME
+#endif  // HAVE_TRUSTED_NAME
diff --git a/src_features/getChallenge/cmd_get_challenge.c b/src_features/getChallenge/cmd_get_challenge.c
index 93e52d9df..84898aa2f 100644
--- a/src_features/getChallenge/cmd_get_challenge.c
+++ b/src_features/getChallenge/cmd_get_challenge.c
@@ -1,4 +1,4 @@
-#ifdef HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
 
 #include <os.h>
 #include <os_io.h>
@@ -27,12 +27,11 @@ uint32_t get_challenge(void) {
 /**
  * Send back the current challenge
  */
-void handle_get_challenge(void) {
+uint16_t handle_get_challenge(unsigned int *tx) {
     PRINTF("New challenge -> %u\n", get_challenge());
     U4BE_ENCODE(G_io_apdu_buffer, 0, get_challenge());
-    U2BE_ENCODE(G_io_apdu_buffer, 4, APDU_RESPONSE_OK);
-
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 6);
+    *tx += 4;
+    return APDU_RESPONSE_OK;
 }
 
-#endif  // HAVE_DOMAIN_NAME
+#endif  // HAVE_TRUSTED_NAME
diff --git a/src_features/getEth2PublicKey/cmd_getEth2PublicKey.c b/src_features/getEth2PublicKey/cmd_getEth2PublicKey.c
index 995598053..6f282d6da 100644
--- a/src_features/getEth2PublicKey/cmd_getEth2PublicKey.c
+++ b/src_features/getEth2PublicKey/cmd_getEth2PublicKey.c
@@ -12,77 +12,84 @@ static const uint8_t BLS12_381_FIELD_MODULUS[] = {
     0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24,
     0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab};
 
-void getEth2PublicKey(uint32_t *bip32Path, uint8_t bip32PathLength, uint8_t *out) {
+uint32_t getEth2PublicKey(uint32_t *bip32Path, uint8_t bip32PathLength, uint8_t *out) {
     uint8_t privateKeyData[64];
     cx_ecfp_256_extended_private_key_t privateKey;
     cx_ecfp_384_public_key_t publicKey;
     uint8_t yFlag = 0;
     uint8_t tmp[96];
     int diff;
+    cx_err_t error = CX_INTERNAL_ERROR;
 
     io_seproxyhal_io_heartbeat();
-    CX_ASSERT(os_derive_eip2333_no_throw(CX_CURVE_BLS12_381_G1,
-                                         bip32Path,
-                                         bip32PathLength,
-                                         privateKeyData));
+    CX_CHECK(os_derive_eip2333_no_throw(CX_CURVE_BLS12_381_G1,
+                                        bip32Path,
+                                        bip32PathLength,
+                                        privateKeyData));
     io_seproxyhal_io_heartbeat();
     memset(tmp, 0, 48);
     memmove(tmp + 16, privateKeyData, 32);
-    CX_ASSERT(cx_ecfp_init_private_key_no_throw(CX_CURVE_BLS12_381_G1,
-                                                tmp,
-                                                48,
-                                                (cx_ecfp_private_key_t *) &privateKey));
-    CX_ASSERT(cx_ecfp_generate_pair_no_throw(CX_CURVE_BLS12_381_G1,
-                                             (cx_ecfp_public_key_t *) &publicKey,
-                                             (cx_ecfp_private_key_t *) &privateKey,
-                                             1));
+    CX_CHECK(cx_ecfp_init_private_key_no_throw(CX_CURVE_BLS12_381_G1,
+                                               tmp,
+                                               48,
+                                               (cx_ecfp_private_key_t *) &privateKey));
+    CX_CHECK(cx_ecfp_generate_pair_no_throw(CX_CURVE_BLS12_381_G1,
+                                            (cx_ecfp_public_key_t *) &publicKey,
+                                            (cx_ecfp_private_key_t *) &privateKey,
+                                            1));
     explicit_bzero(tmp, 96);
-    explicit_bzero((void *) &privateKey, sizeof(cx_ecfp_256_extended_private_key_t));
     tmp[47] = 2;
-    CX_ASSERT(cx_math_mult_no_throw(tmp, publicKey.W + 1 + 48, tmp, 48));
-    CX_ASSERT(cx_math_cmp_no_throw(tmp + 48, BLS12_381_FIELD_MODULUS, 48, &diff));
+    CX_CHECK(cx_math_mult_no_throw(tmp, publicKey.W + 1 + 48, tmp, 48));
+    CX_CHECK(cx_math_cmp_no_throw(tmp + 48, BLS12_381_FIELD_MODULUS, 48, &diff));
     if (diff > 0) {
         yFlag = 0x20;
     }
     publicKey.W[1] &= 0x1f;
     publicKey.W[1] |= 0x80 | yFlag;
     memmove(out, publicKey.W + 1, 48);
+end:
+    explicit_bzero(tmp, 96);
+    explicit_bzero((void *) &privateKey, sizeof(cx_ecfp_256_extended_private_key_t));
+    return error;
 }
 
-void handleGetEth2PublicKey(uint8_t p1,
-                            uint8_t p2,
-                            const uint8_t *dataBuffer,
-                            uint8_t dataLength,
-                            unsigned int *flags,
-                            unsigned int *tx) {
+uint16_t handleGetEth2PublicKey(uint8_t p1,
+                                uint8_t p2,
+                                const uint8_t *dataBuffer,
+                                uint8_t dataLength,
+                                unsigned int *flags,
+                                unsigned int *tx) {
     bip32_path_t bip32;
+    cx_err_t error = CX_INTERNAL_ERROR;
 
     if (!G_called_from_swap) {
         reset_app_context();
     }
     if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
-        THROW(0x6B00);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
     if (p2 != 0) {
-        THROW(0x6B00);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
 
     dataBuffer = parseBip32(dataBuffer, &dataLength, &bip32);
 
     if (dataBuffer == NULL) {
-        THROW(0x6a80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
-    getEth2PublicKey(bip32.path, bip32.length, tmpCtx.publicKeyContext.publicKey.W);
+    CX_CHECK(getEth2PublicKey(bip32.path, bip32.length, tmpCtx.publicKeyContext.publicKey.W));
 
     if (p1 == P1_NON_CONFIRM) {
         *tx = set_result_get_eth2_publicKey();
-        THROW(0x9000);
-    } else {
-        ui_display_public_eth2();
-
-        *flags |= IO_ASYNCH_REPLY;
+        return APDU_RESPONSE_OK;
     }
+    ui_display_public_eth2();
+    *flags |= IO_ASYNCH_REPLY;
+    // Return code will be sent after UI approve/cancel
+    error = 0;
+end:
+    return error;
 }
 
 #endif
diff --git a/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c b/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c
index 77b38c0e3..81dbea90d 100644
--- a/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c
+++ b/src_features/getEth2PublicKey/ui_common_getEth2PublicKey.c
@@ -1,32 +1,13 @@
 #ifdef HAVE_ETH2
 
 #include "shared_context.h"
+#include "apdu_constants.h"
 #include "feature_getEth2PublicKey.h"
 #include "common_ui.h"
 
-unsigned int io_seproxyhal_touch_eth2_address_ok(__attribute__((unused)) const bagl_element_t *e) {
+unsigned int io_seproxyhal_touch_eth2_address_ok(void) {
     uint32_t tx = set_result_get_eth2_publicKey();
-    G_io_apdu_buffer[tx++] = 0x90;
-    G_io_apdu_buffer[tx++] = 0x00;
-    reset_app_context();
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+    return io_seproxyhal_send_status(APDU_RESPONSE_OK, tx, true, true);
 }
 
-#if 0
-unsigned int io_seproxyhal_touch_eth2_address_cancel(const bagl_element_t *e) {
-    G_io_apdu_buffer[0] = 0x69;
-    G_io_apdu_buffer[1] = 0x85;
-    reset_app_context();
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
-    // Display back the original UX
-    ui_idle();
-    return 0; // do not redraw the widget
-}
-#endif
-
 #endif
diff --git a/src_features/getPublicKey/cmd_getPublicKey.c b/src_features/getPublicKey/cmd_getPublicKey.c
index 66a4b4c32..39d6702cd 100644
--- a/src_features/getPublicKey/cmd_getPublicKey.c
+++ b/src_features/getPublicKey/cmd_getPublicKey.c
@@ -6,13 +6,14 @@
 #include "os_io_seproxyhal.h"
 #include "crypto_helpers.h"
 
-void handleGetPublicKey(uint8_t p1,
-                        uint8_t p2,
-                        const uint8_t *dataBuffer,
-                        uint8_t dataLength,
-                        unsigned int *flags,
-                        unsigned int *tx) {
+uint16_t handleGetPublicKey(uint8_t p1,
+                            uint8_t p2,
+                            const uint8_t *dataBuffer,
+                            uint8_t dataLength,
+                            unsigned int *flags,
+                            unsigned int *tx) {
     bip32_path_t bip32;
+    cx_err_t error = CX_INTERNAL_ERROR;
 
     if (!G_called_from_swap) {
         reset_app_context();
@@ -20,29 +21,26 @@ void handleGetPublicKey(uint8_t p1,
 
     if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
         PRINTF("Error: Unexpected P1 (%u)!\n", p1);
-        THROW(APDU_RESPONSE_INVALID_P1_P2);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
     if ((p2 != P2_CHAINCODE) && (p2 != P2_NO_CHAINCODE)) {
         PRINTF("Error: Unexpected P2 (%u)!\n", p2);
-        THROW(APDU_RESPONSE_INVALID_P1_P2);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
 
     dataBuffer = parseBip32(dataBuffer, &dataLength, &bip32);
-
     if (dataBuffer == NULL) {
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     tmpCtx.publicKeyContext.getChaincode = (p2 == P2_CHAINCODE);
-    if (bip32_derive_get_pubkey_256(
-            CX_CURVE_256K1,
-            bip32.path,
-            bip32.length,
-            tmpCtx.publicKeyContext.publicKey.W,
-            (tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL),
-            CX_SHA512) != CX_OK) {
-        THROW(APDU_RESPONSE_UNKNOWN);
-    }
+    CX_CHECK(bip32_derive_get_pubkey_256(
+        CX_CURVE_256K1,
+        bip32.path,
+        bip32.length,
+        tmpCtx.publicKeyContext.publicKey.W,
+        (tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL),
+        CX_SHA512));
     getEthAddressStringFromRawKey(tmpCtx.publicKeyContext.publicKey.W,
                                   tmpCtx.publicKeyContext.address,
                                   chainConfig->chainId);
@@ -57,21 +55,23 @@ void handleGetPublicKey(uint8_t p1,
     (void) dataBuffer;  // to prevent dead increment warning
     if (dataLength > 0) {
         PRINTF("Error: Leftover unwanted data (%u bytes long)!\n", dataLength);
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     if (p1 == P1_NON_CONFIRM) {
         *tx = set_result_get_publicKey();
-        THROW(APDU_RESPONSE_OK);
-    } else {
-        snprintf(strings.common.toAddress,
-                 sizeof(strings.common.toAddress),
-                 "0x%.*s",
-                 40,
-                 tmpCtx.publicKeyContext.address);
-        // don't unnecessarily pass the current app's chain ID
-        ui_display_public_key(chainConfig->chainId == chain_id ? NULL : &chain_id);
-
-        *flags |= IO_ASYNCH_REPLY;
+        return APDU_RESPONSE_OK;
     }
+    snprintf(strings.common.toAddress,
+             sizeof(strings.common.toAddress),
+             "0x%.*s",
+             40,
+             tmpCtx.publicKeyContext.address);
+    // don't unnecessarily pass the current app's chain ID
+    ui_display_public_key(chainConfig->chainId == chain_id ? NULL : &chain_id);
+    *flags |= IO_ASYNCH_REPLY;
+    // Return code will be sent after UI approve/cancel
+    error = 0;
+end:
+    return error;
 }
diff --git a/src_features/getPublicKey/ui_common_getPublicKey.c b/src_features/getPublicKey/ui_common_getPublicKey.c
index d38724a36..fe1a0bae0 100644
--- a/src_features/getPublicKey/ui_common_getPublicKey.c
+++ b/src_features/getPublicKey/ui_common_getPublicKey.c
@@ -1,26 +1,13 @@
 #include "shared_context.h"
+#include "apdu_constants.h"
 #include "feature_getPublicKey.h"
 #include "common_ui.h"
 
-unsigned int io_seproxyhal_touch_address_ok(__attribute__((unused)) const bagl_element_t *e) {
+unsigned int io_seproxyhal_touch_address_ok(void) {
     uint32_t tx = set_result_get_publicKey();
-    G_io_apdu_buffer[tx++] = 0x90;
-    G_io_apdu_buffer[tx++] = 0x00;
-    reset_app_context();
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+    return io_seproxyhal_send_status(APDU_RESPONSE_OK, tx, true, false);
 }
 
-unsigned int io_seproxyhal_touch_address_cancel(__attribute__((unused)) const bagl_element_t *e) {
-    G_io_apdu_buffer[0] = 0x69;
-    G_io_apdu_buffer[1] = 0x85;
-    reset_app_context();
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+unsigned int io_seproxyhal_touch_address_cancel(void) {
+    return io_seproxyhal_send_status(APDU_RESPONSE_CONDITION_NOT_SATISFIED, 0, true, false);
 }
diff --git a/src_features/performPrivacyOperation/cmd_performPrivacyOperation.c b/src_features/performPrivacyOperation/cmd_performPrivacyOperation.c
index e1a733f45..6b5b6b3e1 100644
--- a/src_features/performPrivacyOperation/cmd_performPrivacyOperation.c
+++ b/src_features/performPrivacyOperation/cmd_performPrivacyOperation.c
@@ -23,96 +23,92 @@ void decodeScalar(const uint8_t *scalarIn, uint8_t *scalarOut) {
     }
 }
 
-void handlePerformPrivacyOperation(uint8_t p1,
-                                   uint8_t p2,
-                                   const uint8_t *dataBuffer,
-                                   uint8_t dataLength,
-                                   unsigned int *flags,
-                                   unsigned int *tx) {
+uint16_t handlePerformPrivacyOperation(uint8_t p1,
+                                       uint8_t p2,
+                                       const uint8_t *dataBuffer,
+                                       uint8_t dataLength,
+                                       unsigned int *flags,
+                                       unsigned int *tx) {
+    cx_ecfp_private_key_t privateKey;
     uint8_t privateKeyData[64];
     uint8_t privateKeyDataSwapped[INT256_LENGTH];
     bip32_path_t bip32;
-    cx_err_t status = CX_OK;
+    cx_err_t error = CX_INTERNAL_ERROR;
 
     if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
-        THROW(0x6B00);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
 
     if ((p2 != P2_PUBLIC_ENCRYPTION_KEY) && (p2 != P2_SHARED_SECRET)) {
-        THROW(0x6700);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
 
     dataBuffer = parseBip32(dataBuffer, &dataLength, &bip32);
-
     if (dataBuffer == NULL) {
-        THROW(0x6a80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     if ((p2 == P2_SHARED_SECRET) && (dataLength < 32)) {
-        THROW(0x6700);
+        return APDU_RESPONSE_WRONG_DATA_LENGTH;
     }
 
-    cx_ecfp_private_key_t privateKey;
-
-    CX_ASSERT(os_derive_bip32_no_throw(
+    CX_CHECK(os_derive_bip32_no_throw(
         CX_CURVE_256K1,
         bip32.path,
         bip32.length,
         privateKeyData,
         (tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL)));
-    CX_ASSERT(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32, &privateKey));
-    CX_ASSERT(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1,
-                                             &tmpCtx.publicKeyContext.publicKey,
-                                             &privateKey,
-                                             1));
+    CX_CHECK(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32, &privateKey));
+    CX_CHECK(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1,
+                                            &tmpCtx.publicKeyContext.publicKey,
+                                            &privateKey,
+                                            1));
     getEthAddressStringFromRawKey((const uint8_t *) &tmpCtx.publicKeyContext.publicKey.W,
                                   tmpCtx.publicKeyContext.address,
                                   chainConfig->chainId);
     if (p2 == P2_PUBLIC_ENCRYPTION_KEY) {
         decodeScalar(privateKeyData, privateKeyDataSwapped);
-        CX_ASSERT(cx_ecfp_init_private_key_no_throw(CX_CURVE_Curve25519,
-                                                    privateKeyDataSwapped,
-                                                    32,
-                                                    &privateKey));
-        CX_ASSERT(cx_ecfp_generate_pair_no_throw(CX_CURVE_Curve25519,
-                                                 &tmpCtx.publicKeyContext.publicKey,
-                                                 &privateKey,
-                                                 1));
-        explicit_bzero(privateKeyDataSwapped, sizeof(privateKeyDataSwapped));
+        CX_CHECK(cx_ecfp_init_private_key_no_throw(CX_CURVE_Curve25519,
+                                                   privateKeyDataSwapped,
+                                                   32,
+                                                   &privateKey));
+        CX_CHECK(cx_ecfp_generate_pair_no_throw(CX_CURVE_Curve25519,
+                                                &tmpCtx.publicKeyContext.publicKey,
+                                                &privateKey,
+                                                1));
     } else {
         memmove(tmpCtx.publicKeyContext.publicKey.W + 1, dataBuffer, 32);
-        status = cx_x25519(tmpCtx.publicKeyContext.publicKey.W + 1, privateKeyData, 32);
-    }
-    explicit_bzero(&privateKey, sizeof(privateKey));
-    explicit_bzero(privateKeyData, sizeof(privateKeyData));
-
-    if (status != CX_OK) {
-        THROW(0x6A80);
+        CX_CHECK(cx_x25519(tmpCtx.publicKeyContext.publicKey.W + 1, privateKeyData, 32));
     }
 
     if (p1 == P1_NON_CONFIRM) {
         *tx = set_result_perform_privacy_operation();
-        THROW(0x9000);
-    } else {
-        snprintf(strings.common.toAddress,
-                 sizeof(strings.common.toAddress),
-                 "0x%.*s",
-                 40,
-                 tmpCtx.publicKeyContext.address);
-        for (uint8_t i = 0; i < 32; i++) {
-            privateKeyData[i] = tmpCtx.publicKeyContext.publicKey.W[32 - i];
-        }
-        format_hex(privateKeyData,
-                   32,
-                   strings.common.fullAmount,
-                   sizeof(strings.common.fullAmount) - 1);
-
-        if (p2 == P2_PUBLIC_ENCRYPTION_KEY) {
-            ui_display_privacy_public_key();
-        } else {
-            ui_display_privacy_shared_secret();
-        }
+        return APDU_RESPONSE_OK;
+    }
+    snprintf(strings.common.toAddress,
+             sizeof(strings.common.toAddress),
+             "0x%.*s",
+             40,
+             tmpCtx.publicKeyContext.address);
+    for (uint8_t i = 0; i < 32; i++) {
+        privateKeyData[i] = tmpCtx.publicKeyContext.publicKey.W[32 - i];
+    }
+    format_hex(privateKeyData,
+               32,
+               strings.common.fullAmount,
+               sizeof(strings.common.fullAmount) - 1);
 
-        *flags |= IO_ASYNCH_REPLY;
+    if (p2 == P2_PUBLIC_ENCRYPTION_KEY) {
+        ui_display_privacy_public_key();
+    } else {
+        ui_display_privacy_shared_secret();
     }
+    *flags |= IO_ASYNCH_REPLY;
+    // Return code will be sent after UI approve/cancel
+    error = 0;
+end:
+    explicit_bzero(privateKeyDataSwapped, sizeof(privateKeyDataSwapped));
+    explicit_bzero(&privateKey, sizeof(privateKey));
+    explicit_bzero(privateKeyData, sizeof(privateKeyData));
+    return error;
 }
diff --git a/src_features/performPrivacyOperation/ui_common_performPrivacyOperation.c b/src_features/performPrivacyOperation/ui_common_performPrivacyOperation.c
index a2cb1c3d7..652e6be11 100644
--- a/src_features/performPrivacyOperation/ui_common_performPrivacyOperation.c
+++ b/src_features/performPrivacyOperation/ui_common_performPrivacyOperation.c
@@ -1,27 +1,14 @@
 #include "shared_context.h"
+#include "apdu_constants.h"
 #include "feature_getPublicKey.h"
 #include "common_ui.h"
 #include "feature_performPrivacyOperation.h"
 
-unsigned int io_seproxyhal_touch_privacy_ok(__attribute__((unused)) const bagl_element_t *e) {
+unsigned int io_seproxyhal_touch_privacy_ok(void) {
     uint32_t tx = set_result_perform_privacy_operation();
-    G_io_apdu_buffer[tx++] = 0x90;
-    G_io_apdu_buffer[tx++] = 0x00;
-    reset_app_context();
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+    return io_seproxyhal_send_status(APDU_RESPONSE_OK, tx, true, true);
 }
 
-unsigned int io_seproxyhal_touch_privacy_cancel(__attribute__((unused)) const bagl_element_t *e) {
-    G_io_apdu_buffer[0] = 0x69;
-    G_io_apdu_buffer[1] = 0x85;
-    reset_app_context();
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+unsigned int io_seproxyhal_touch_privacy_cancel(void) {
+    return io_seproxyhal_send_status(APDU_RESPONSE_CONDITION_NOT_SATISFIED, 0, true, true);
 }
diff --git a/src_features/provideDomainName/cmd_provide_domain_name.c b/src_features/provideDomainName/cmd_provide_domain_name.c
deleted file mode 100644
index cfcdc0ddf..000000000
--- a/src_features/provideDomainName/cmd_provide_domain_name.c
+++ /dev/null
@@ -1,707 +0,0 @@
-#ifdef HAVE_DOMAIN_NAME
-
-#include <os.h>
-#include <stdint.h>
-#include <string.h>
-#include <ctype.h>
-#include "common_utils.h"  // ARRAY_SIZE
-#include "apdu_constants.h"
-#include "domain_name.h"
-#include "challenge.h"
-#include "mem.h"
-#include "hash_bytes.h"
-#include "network.h"
-#include "public_keys.h"
-
-#define P1_FIRST_CHUNK     0x01
-#define P1_FOLLOWING_CHUNK 0x00
-
-#define ALGO_SECP256K1 1
-
-#define SLIP_44_ETHEREUM 60
-
-#define DER_LONG_FORM_FLAG        0x80  // 8th bit set
-#define DER_FIRST_BYTE_VALUE_MASK 0x7f
-
-typedef enum { TLV_TAG, TLV_LENGTH, TLV_VALUE } e_tlv_step;
-
-typedef enum {
-    STRUCTURE_TYPE = 0x01,
-    STRUCTURE_VERSION = 0x02,
-    CHALLENGE = 0x12,
-    SIGNER_KEY_ID = 0x13,
-    SIGNER_ALGO = 0x14,
-    SIGNATURE = 0x15,
-    DOMAIN_NAME = 0x20,
-    COIN_TYPE = 0x21,
-    ADDRESS = 0x22
-} e_tlv_tag;
-
-typedef enum { KEY_ID_TEST = 0x00, KEY_ID_PROD = 0x03 } e_key_id;
-
-typedef struct {
-    uint8_t *buf;
-    uint16_t size;
-    uint16_t expected_size;
-} s_tlv_payload;
-
-typedef struct {
-    e_tlv_tag tag;
-    uint8_t length;
-    const uint8_t *value;
-} s_tlv_data;
-
-typedef struct {
-    bool valid;
-    char *name;
-    uint8_t addr[ADDRESS_LENGTH];
-} s_domain_name_info;
-
-typedef struct {
-    e_key_id key_id;
-    uint8_t input_sig_size;
-    const uint8_t *input_sig;
-    cx_sha256_t hash_ctx;
-} s_sig_ctx;
-
-typedef bool(t_tlv_handler)(const s_tlv_data *data,
-                            s_domain_name_info *domain_name_info,
-                            s_sig_ctx *sig_ctx);
-
-typedef struct {
-    uint8_t tag;
-    t_tlv_handler *func;
-    uint8_t found;
-} s_tlv_handler;
-
-static s_tlv_payload g_tlv_payload = {0};
-static s_domain_name_info g_domain_name_info;
-char g_domain_name[DOMAIN_NAME_MAX_LENGTH + 1];
-
-/**
- * Send a response APDU
- *
- * @param[in] success whether it should use \ref APDU_RESPONSE_OK
- * @param[in] off payload offset (0 if no data other than status word)
- */
-static void response_to_domain_name(bool success, uint8_t off) {
-    uint16_t sw;
-
-    if (success) {
-        sw = APDU_RESPONSE_OK;
-    } else {
-        sw = apdu_response_code;
-    }
-    U2BE_ENCODE(G_io_apdu_buffer, off, sw);
-
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, off + 2);
-}
-
-/**
- * Checks if a domain name for the given chain ID and address is known
- *
- * Always wipes the content of \ref g_domain_name_info
- *
- * @param[in] chain_id given chain ID
- * @param[in] addr given address
- * @return whether there is or not
- */
-bool has_domain_name(const uint64_t *chain_id, const uint8_t *addr) {
-    bool ret = false;
-
-    if (g_domain_name_info.valid) {
-        // 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;
-        }
-    }
-    memset(&g_domain_name_info, 0, sizeof(g_domain_name_info));
-    return ret;
-}
-
-/**
- * Get uint from tlv data
- *
- * Get an unsigned integer from variable length tlv data (up to 4 bytes)
- *
- * @param[in] data tlv data
- * @param[out] value the returned value
- * @return whether it was successful
- */
-static bool get_uint_from_data(const s_tlv_data *data, uint32_t *value) {
-    uint8_t size_diff;
-    uint8_t buffer[sizeof(uint32_t)];
-
-    if (data->length > sizeof(buffer)) {
-        PRINTF("Unexpectedly long value (%u bytes) for tag 0x%x\n", data->length, data->tag);
-        return false;
-    }
-    size_diff = sizeof(buffer) - data->length;
-    memset(buffer, 0, size_diff);
-    memcpy(buffer + size_diff, data->value, data->length);
-    *value = U4BE(buffer, 0);
-    return true;
-}
-
-/**
- * Handler for tag \ref STRUCTURE_TYPE
- *
- * @param[] data the tlv data
- * @param[] domain_name_info the domain name information
- * @param[] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_structure_type(const s_tlv_data *data,
-                                  s_domain_name_info *domain_name_info,
-                                  s_sig_ctx *sig_ctx) {
-    (void) data;
-    (void) domain_name_info;
-    (void) sig_ctx;
-    return true;  // unhandled for now
-}
-
-/**
- * Handler for tag \ref STRUCTURE_VERSION
- *
- * @param[] data the tlv data
- * @param[] domain_name_info the domain name information
- * @param[] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_structure_version(const s_tlv_data *data,
-                                     s_domain_name_info *domain_name_info,
-                                     s_sig_ctx *sig_ctx) {
-    (void) data;
-    (void) domain_name_info;
-    (void) sig_ctx;
-    return true;  // unhandled for now
-}
-
-/**
- * Handler for tag \ref CHALLENGE
- *
- * @param[in] data the tlv data
- * @param[] domain_name_info the domain name information
- * @param[] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_challenge(const s_tlv_data *data,
-                             s_domain_name_info *domain_name_info,
-                             s_sig_ctx *sig_ctx) {
-    uint32_t value;
-    (void) domain_name_info;
-    (void) sig_ctx;
-
-    if (!get_uint_from_data(data, &value)) {
-        return false;
-    }
-    return (value == get_challenge());
-}
-
-/**
- * Handler for tag \ref SIGNER_KEY_ID
- *
- * @param[in] data the tlv data
- * @param[] domain_name_info the domain name information
- * @param[out] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_sign_key_id(const s_tlv_data *data,
-                               s_domain_name_info *domain_name_info,
-                               s_sig_ctx *sig_ctx) {
-    uint32_t value;
-    (void) domain_name_info;
-
-    if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) {
-        return false;
-    }
-    sig_ctx->key_id = value;
-    return true;
-}
-
-/**
- * Handler for tag \ref SIGNER_ALGO
- *
- * @param[in] data the tlv data
- * @param[] domain_name_info the domain name information
- * @param[] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_sign_algo(const s_tlv_data *data,
-                             s_domain_name_info *domain_name_info,
-                             s_sig_ctx *sig_ctx) {
-    uint32_t value;
-
-    (void) domain_name_info;
-    (void) sig_ctx;
-    if (!get_uint_from_data(data, &value)) {
-        return false;
-    }
-    return (value == ALGO_SECP256K1);
-}
-
-/**
- * Handler for tag \ref SIGNATURE
- *
- * @param[in] data the tlv data
- * @param[] domain_name_info the domain name information
- * @param[out] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_signature(const s_tlv_data *data,
-                             s_domain_name_info *domain_name_info,
-                             s_sig_ctx *sig_ctx) {
-    (void) domain_name_info;
-    sig_ctx->input_sig_size = data->length;
-    sig_ctx->input_sig = data->value;
-    return true;
-}
-
-/**
- * Tests if the given domain name character is valid (in our subset of allowed characters)
- *
- * @param[in] c given character
- * @return whether the character is valid
- */
-static bool is_valid_domain_character(char c) {
-    if (isalpha((int) c)) {
-        if (!islower((int) c)) {
-            return false;
-        }
-    } else if (!isdigit((int) c)) {
-        switch (c) {
-            case '.':
-            case '-':
-            case '_':
-                break;
-            default:
-                return false;
-        }
-    }
-    return true;
-}
-
-/**
- * Handler for tag \ref DOMAIN_NAME
- *
- * @param[in] data the tlv data
- * @param[out] domain_name_info the domain name information
- * @param[] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_domain_name(const s_tlv_data *data,
-                               s_domain_name_info *domain_name_info,
-                               s_sig_ctx *sig_ctx) {
-    (void) sig_ctx;
-    if (data->length > DOMAIN_NAME_MAX_LENGTH) {
-        PRINTF("Domain name too long! (%u)\n", data->length);
-        return false;
-    }
-    // TODO: Remove once other domain name providers are supported
-    if ((data->length < 5) || (strncmp(".eth", (char *) &data->value[data->length - 4], 4) != 0)) {
-        PRINTF("Unexpected TLD!\n");
-        return false;
-    }
-    for (int idx = 0; idx < data->length; ++idx) {
-        if (!is_valid_domain_character(data->value[idx])) {
-            PRINTF("Domain name contains non-allowed character! (0x%x)\n", data->value[idx]);
-            return false;
-        }
-        domain_name_info->name[idx] = data->value[idx];
-    }
-    domain_name_info->name[data->length] = '\0';
-    return true;
-}
-
-/**
- * Handler for tag \ref COIN_TYPE
- *
- * @param[in] data the tlv data
- * @param[] domain_name_info the domain name information
- * @param[] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_coin_type(const s_tlv_data *data,
-                             s_domain_name_info *domain_name_info,
-                             s_sig_ctx *sig_ctx) {
-    uint32_t value;
-
-    (void) domain_name_info;
-    (void) sig_ctx;
-    if (!get_uint_from_data(data, &value)) {
-        return false;
-    }
-    return (value == SLIP_44_ETHEREUM);
-}
-
-/**
- * Handler for tag \ref ADDRESS
- *
- * @param[in] data the tlv data
- * @param[out] domain_name_info the domain name information
- * @param[] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_address(const s_tlv_data *data,
-                           s_domain_name_info *domain_name_info,
-                           s_sig_ctx *sig_ctx) {
-    (void) sig_ctx;
-    if (data->length != ADDRESS_LENGTH) {
-        return false;
-    }
-    memcpy(domain_name_info->addr, data->value, ADDRESS_LENGTH);
-    return true;
-}
-
-/**
- * Verify the signature context
- *
- * Verify the SHA-256 hash of the payload against the public key
- *
- * @param[in] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool verify_signature(const s_sig_ctx *sig_ctx) {
-    uint8_t hash[INT256_LENGTH];
-    cx_ecfp_public_key_t verif_key;
-    cx_err_t error = CX_INTERNAL_ERROR;
-
-    CX_CHECK(
-        cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH));
-    switch (sig_ctx->key_id) {
-#ifdef HAVE_DOMAIN_NAME_TEST_KEY
-        case KEY_ID_TEST:
-#else
-        case KEY_ID_PROD:
-#endif
-            CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1,
-                                                      DOMAIN_NAME_PUB_KEY,
-                                                      sizeof(DOMAIN_NAME_PUB_KEY),
-                                                      &verif_key));
-            break;
-        default:
-            PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id);
-            return false;
-    }
-    if (!cx_ecdsa_verify_no_throw(&verif_key,
-                                  hash,
-                                  sizeof(hash),
-                                  sig_ctx->input_sig,
-                                  sig_ctx->input_sig_size)) {
-        PRINTF("Domain name signature verification failed!\n");
-#ifndef HAVE_BYPASS_SIGNATURES
-        return false;
-#endif
-    }
-    return true;
-end:
-    return false;
-}
-
-/**
- * Calls the proper handler for the given TLV data
- *
- * Checks if there is a proper handler function for the given TLV tag and then calls it
- *
- * @param[in] handlers list of tag / handler function pairs
- * @param[in] handler_count number of handlers
- * @param[in] data the TLV data
- * @param[out] domain_name_info the domain name information
- * @param[out] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool handle_tlv_data(s_tlv_handler *handlers,
-                            int handler_count,
-                            const s_tlv_data *data,
-                            s_domain_name_info *domain_name_info,
-                            s_sig_ctx *sig_ctx) {
-    t_tlv_handler *fptr;
-
-    // check if a handler exists for this tag
-    for (int idx = 0; idx < handler_count; ++idx) {
-        if (handlers[idx].tag == data->tag) {
-            handlers[idx].found += 1;
-            fptr = PIC(handlers[idx].func);
-            if (!(*fptr)(data, domain_name_info, sig_ctx)) {
-                PRINTF("Error while handling tag 0x%x\n", handlers[idx].tag);
-                return false;
-            }
-            break;
-        }
-    }
-    return true;
-}
-
-/**
- * Checks if all the TLV tags were found during parsing
- *
- * @param[in,out] handlers list of tag / handler function pairs
- * @param[in] handler_count number of handlers
- * @return whether all tags were found
- */
-static bool check_found_tlv_tags(s_tlv_handler *handlers, int handler_count) {
-    // prevent missing or duplicated tags
-    for (int idx = 0; idx < handler_count; ++idx) {
-        if (handlers[idx].found != 1) {
-            PRINTF("Found %u occurrence(s) of tag 0x%x in TLV!\n",
-                   handlers[idx].found,
-                   handlers[idx].tag);
-            return false;
-        }
-    }
-    return true;
-}
-
-/** Parse DER-encoded value
- *
- * Parses a DER-encoded value (up to 4 bytes long)
- * https://en.wikipedia.org/wiki/X.690
- *
- * @param[in] payload the TLV payload
- * @param[in,out] offset the payload offset
- * @param[out] value the parsed value
- * @return whether it was successful
- */
-static bool parse_der_value(const s_tlv_payload *payload, size_t *offset, uint32_t *value) {
-    bool ret = false;
-    uint8_t byte_length;
-    uint8_t buf[sizeof(*value)];
-
-    if (value != NULL) {
-        if (payload->buf[*offset] & DER_LONG_FORM_FLAG) {  // long form
-            byte_length = payload->buf[*offset] & DER_FIRST_BYTE_VALUE_MASK;
-            *offset += 1;
-            if ((*offset + byte_length) > payload->size) {
-                PRINTF("TLV payload too small for DER encoded value\n");
-            } else {
-                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));
-                    memcpy(buf + (sizeof(buf) - byte_length), &payload->buf[*offset], byte_length);
-                    *value = U4BE(buf, 0);
-                    *offset += byte_length;
-                    ret = true;
-                }
-            }
-        } else {  // short form
-            *value = payload->buf[*offset];
-            *offset += 1;
-            ret = true;
-        }
-    }
-    return ret;
-}
-
-/**
- * Get DER-encoded value as an uint8
- *
- * Parses the value and checks if it fits in the given \ref uint8_t value
- *
- * @param[in] payload the TLV payload
- * @param[in,out] offset
- * @param[out] value the parsed value
- * @return whether it was successful
- */
-static bool get_der_value_as_uint8(const s_tlv_payload *payload, size_t *offset, uint8_t *value) {
-    bool ret = false;
-    uint32_t tmp_value;
-
-    if (value != NULL) {
-        if (!parse_der_value(payload, offset, &tmp_value)) {
-            apdu_response_code = APDU_RESPONSE_INVALID_DATA;
-        } else {
-            if (tmp_value <= UINT8_MAX) {
-                *value = tmp_value;
-                ret = true;
-            } else {
-                apdu_response_code = APDU_RESPONSE_INVALID_DATA;
-                PRINTF("TLV DER-encoded value larger than 8 bits\n");
-            }
-        }
-    }
-    return ret;
-}
-
-/**
- * Parse the TLV payload
- *
- * Does the TLV parsing but also the SHA-256 hash of the payload.
- *
- * @param[in] payload the raw TLV payload
- * @param[out] domain_name_info the domain name information
- * @param[out] sig_ctx the signature context
- * @return whether it was successful
- */
-static bool parse_tlv(const s_tlv_payload *payload,
-                      s_domain_name_info *domain_name_info,
-                      s_sig_ctx *sig_ctx) {
-    s_tlv_handler handlers[] = {
-        {.tag = STRUCTURE_TYPE, .func = &handle_structure_type, .found = 0},
-        {.tag = STRUCTURE_VERSION, .func = &handle_structure_version, .found = 0},
-        {.tag = CHALLENGE, .func = &handle_challenge, .found = 0},
-        {.tag = SIGNER_KEY_ID, .func = &handle_sign_key_id, .found = 0},
-        {.tag = SIGNER_ALGO, .func = &handle_sign_algo, .found = 0},
-        {.tag = SIGNATURE, .func = &handle_signature, .found = 0},
-        {.tag = DOMAIN_NAME, .func = &handle_domain_name, .found = 0},
-        {.tag = COIN_TYPE, .func = &handle_coin_type, .found = 0},
-        {.tag = ADDRESS, .func = &handle_address, .found = 0}};
-    e_tlv_step step = TLV_TAG;
-    s_tlv_data data;
-    size_t offset = 0;
-    size_t tag_start_off;
-
-    cx_sha256_init(&sig_ctx->hash_ctx);
-    // handle TLV payload
-    while (offset < payload->size) {
-        switch (step) {
-            case TLV_TAG:
-                tag_start_off = offset;
-                if (!get_der_value_as_uint8(payload, &offset, &data.tag)) {
-                    return false;
-                }
-                step = TLV_LENGTH;
-                break;
-
-            case TLV_LENGTH:
-                if (!get_der_value_as_uint8(payload, &offset, &data.length)) {
-                    return false;
-                }
-                step = TLV_VALUE;
-                break;
-
-            case TLV_VALUE:
-                if (offset >= payload->size) {
-                    return false;
-                }
-                data.value = &payload->buf[offset];
-                if (!handle_tlv_data(handlers,
-                                     ARRAY_SIZE(handlers),
-                                     &data,
-                                     domain_name_info,
-                                     sig_ctx)) {
-                    return false;
-                }
-                offset += data.length;
-                if (data.tag != SIGNATURE) {  // the signature wasn't computed on itself
-                    hash_nbytes(&payload->buf[tag_start_off],
-                                (offset - tag_start_off),
-                                (cx_hash_t *) &sig_ctx->hash_ctx);
-                }
-                step = TLV_TAG;
-                break;
-
-            default:
-                return false;
-        }
-    }
-    return check_found_tlv_tags(handlers, ARRAY_SIZE(handlers));
-}
-
-/**
- * Allocate and assign TLV payload
- *
- * @param[in] payload payload structure
- * @param[in] size size of the payload
- * @return whether it was successful
- */
-static bool alloc_payload(s_tlv_payload *payload, uint16_t size) {
-    if ((payload->buf = mem_alloc(size)) == NULL) {
-        apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
-        return false;
-    }
-    payload->expected_size = size;
-    return true;
-}
-
-/**
- * Deallocate and unassign TLV payload
- *
- * @param[in] payload payload structure
- */
-static void free_payload(s_tlv_payload *payload) {
-    mem_dealloc(payload->expected_size);
-    memset(payload, 0, sizeof(*payload));
-}
-
-static bool handle_first_chunk(const uint8_t **data, uint8_t *length, s_tlv_payload *payload) {
-    // check if no payload is already in memory
-    if (payload->buf != NULL) {
-        free_payload(payload);
-        apdu_response_code = APDU_RESPONSE_INVALID_P1_P2;
-        return false;
-    }
-
-    // check if we at least get the size
-    if (*length < sizeof(payload->expected_size)) {
-        apdu_response_code = APDU_RESPONSE_INVALID_DATA;
-        return false;
-    }
-    if (!alloc_payload(payload, U2BE(*data, 0))) {
-        apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
-        return false;
-    }
-
-    // skip the size so we can process it like a following chunk
-    *data += sizeof(payload->expected_size);
-    *length -= sizeof(payload->expected_size);
-    return true;
-}
-
-/**
- * Handle domain name APDU
- *
- * @param[in] p1 first APDU instruction parameter
- * @param[in] p2 second APDU instruction parameter
- * @param[in] data APDU payload
- * @param[in] length payload size
- */
-void handle_provide_domain_name(uint8_t p1, uint8_t p2, const uint8_t *data, uint8_t length) {
-    s_sig_ctx sig_ctx;
-
-    (void) p2;
-    if (p1 == P1_FIRST_CHUNK) {
-        if (!handle_first_chunk(&data, &length, &g_tlv_payload)) {
-            return response_to_domain_name(false, 0);
-        }
-    } else {
-        // check if a payload is already in memory
-        if (g_tlv_payload.buf == NULL) {
-            apdu_response_code = APDU_RESPONSE_INVALID_P1_P2;
-            return response_to_domain_name(false, 0);
-        }
-    }
-
-    if ((g_tlv_payload.size + length) > g_tlv_payload.expected_size) {
-        apdu_response_code = APDU_RESPONSE_INVALID_DATA;
-        free_payload(&g_tlv_payload);
-        PRINTF("TLV payload size mismatch!\n");
-        return response_to_domain_name(false, 0);
-    }
-    // feed into tlv payload
-    memcpy(g_tlv_payload.buf + g_tlv_payload.size, data, length);
-    g_tlv_payload.size += length;
-
-    // everything has been received
-    if (g_tlv_payload.size == g_tlv_payload.expected_size) {
-        g_domain_name_info.name = g_domain_name;
-        if (!parse_tlv(&g_tlv_payload, &g_domain_name_info, &sig_ctx) ||
-            !verify_signature(&sig_ctx)) {
-            free_payload(&g_tlv_payload);
-            roll_challenge();  // prevent brute-force guesses
-            apdu_response_code = APDU_RESPONSE_INVALID_DATA;
-            return response_to_domain_name(false, 0);
-        }
-        g_domain_name_info.valid = true;
-        PRINTF("Registered : %s => %.*h\n",
-               g_domain_name_info.name,
-               ADDRESS_LENGTH,
-               g_domain_name_info.addr);
-        free_payload(&g_tlv_payload);
-        roll_challenge();  // prevent replays
-    }
-    return response_to_domain_name(true, 0);
-}
-
-#endif  // HAVE_DOMAIN_NAME
diff --git a/src_features/provideDomainName/domain_name.h b/src_features/provideDomainName/domain_name.h
deleted file mode 100644
index 502254f4e..000000000
--- a/src_features/provideDomainName/domain_name.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifdef HAVE_DOMAIN_NAME
-
-#ifndef DOMAIN_NAME_H_
-#define DOMAIN_NAME_H_
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#define DOMAIN_NAME_MAX_LENGTH 30
-
-bool has_domain_name(const uint64_t *chain_id, const uint8_t *addr);
-void handle_provide_domain_name(uint8_t p1, uint8_t p2, const uint8_t *data, uint8_t length);
-
-extern char g_domain_name[DOMAIN_NAME_MAX_LENGTH + 1];
-
-#endif  // DOMAIN_NAME_H_
-
-#endif  // HAVE_DOMAIN_NAME
diff --git a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c
index d5ed912ff..492c5244f 100644
--- a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c
+++ b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c
@@ -3,132 +3,34 @@
 #include "public_keys.h"
 #include "common_ui.h"
 #include "os_io_seproxyhal.h"
-#include "extra_tokens.h"
 #include "network.h"
 #include "manage_asset_info.h"
-
-#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR
-
-void handleProvideErc20TokenInformation(uint8_t p1,
-                                        uint8_t p2,
-                                        const uint8_t *workBuffer,
-                                        uint8_t dataLength,
-                                        unsigned int *flags,
-                                        unsigned int *tx) {
-    UNUSED(p1);
-    UNUSED(p2);
-    UNUSED(flags);
-    uint32_t offset = 0;
-    uint8_t tickerLength, contractNameLength;
-    uint32_t chainId;
-    uint8_t hash[INT256_LENGTH];
-    cx_sha256_t sha256;
-    cx_ecfp_public_key_t tokenKey;
-
-    cx_sha256_init(&sha256);
-
-    tokenDefinition_t *token = &get_current_asset_info()->token;
-
-    if (dataLength < 1) {
-        THROW(0x6A80);
-    }
-    tickerLength = workBuffer[offset++];
-    dataLength--;
-    if ((tickerLength + 2) >= sizeof(token->ticker)) {  // +2 because ' \0' is appended to ticker
-        THROW(0x6A80);
-    }
-    if (dataLength < tickerLength + 1) {
-        THROW(0x6A80);
-    }
-    cx_hash((cx_hash_t *) &sha256, 0, workBuffer + offset, tickerLength, NULL, 0);
-    memmove(token->ticker, workBuffer + offset, tickerLength);
-    token->ticker[tickerLength] = '\0';
-    offset += tickerLength;
-    dataLength -= tickerLength;
-
-    contractNameLength = workBuffer[offset++];
-    dataLength--;
-    if (dataLength < contractNameLength + 20 + 4 + 4) {
-        THROW(0x6A80);
-    }
-    cx_hash((cx_hash_t *) &sha256,
-            CX_LAST,
-            workBuffer + offset,
-            contractNameLength + 20 + 4 + 4,
-            hash,
-            32);
-    memmove(token->contractName,
-            workBuffer + offset,
-            MIN(contractNameLength, sizeof(token->contractName) - 1));
-    token->contractName[MIN(contractNameLength, sizeof(token->contractName) - 1)] = '\0';
-    offset += contractNameLength;
-    dataLength -= contractNameLength;
-
-    memmove(token->address, workBuffer + offset, 20);
-    offset += 20;
-    dataLength -= 20;
-    token->decimals = U4BE(workBuffer, offset);
-    offset += 4;
-    dataLength -= 4;
-    chainId = U4BE(workBuffer, offset);
-    if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
-        PRINTF("ChainId token mismatch\n");
-        THROW(0x6A80);
-    }
-    offset += 4;
-    dataLength -= 4;
-    cx_ecfp_init_public_key(CX_CURVE_256K1,
-                            LEDGER_SIGNATURE_PUBLIC_KEY,
-                            sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
-                            &tokenKey);
-    if (!cx_ecdsa_verify(&tokenKey,
-                         CX_LAST,
-                         CX_SHA256,
-                         hash,
-                         32,
-                         workBuffer + offset,
-                         dataLength)) {
-#ifndef HAVE_BYPASS_SIGNATURES
-        PRINTF("Invalid token signature\n");
-        THROW(0x6A80);
+#ifdef HAVE_LEDGER_PKI
+#include "os_pki.h"
 #endif
-    }
-    validate_current_asset_info();
-    THROW(0x9000);
-}
-
-#else
 
-void handleProvideErc20TokenInformation(uint8_t p1,
-                                        uint8_t p2,
-                                        const uint8_t *workBuffer,
-                                        uint8_t dataLength,
-                                        unsigned int *flags,
-                                        unsigned int *tx) {
-    UNUSED(p1);
-    UNUSED(p2);
-    UNUSED(flags);
-    UNUSED(tx);
+uint16_t handleProvideErc20TokenInformation(const uint8_t *workBuffer,
+                                            uint8_t dataLength,
+                                            unsigned int *tx) {
     uint32_t offset = 0;
     uint8_t tickerLength;
     uint64_t chain_id;
     uint8_t hash[INT256_LENGTH];
-    cx_ecfp_public_key_t tokenKey;
-
     tokenDefinition_t *token = &get_current_asset_info()->token;
+    cx_err_t error = CX_INTERNAL_ERROR;
 
     PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex);
 
     if (dataLength < 1) {
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     tickerLength = workBuffer[offset++];
     dataLength--;
     if ((tickerLength + 1) > sizeof(token->ticker)) {
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     if (dataLength < tickerLength + 20 + 4 + 4) {
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32);
     memmove(token->ticker, workBuffer + offset, tickerLength);
@@ -146,43 +48,30 @@ void handleProvideErc20TokenInformation(uint8_t p1,
     chain_id = U4BE(workBuffer, offset);
     if (!app_compatible_with_chain_id(&chain_id)) {
         UNSUPPORTED_CHAIN_ID_MSG(chain_id);
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += 4;
     dataLength -= 4;
 
-#ifdef HAVE_TOKENS_EXTRA_LIST
-    tokenDefinition_t *currentToken = NULL;
-    uint32_t index;
-    for (index = 0; index < NUM_TOKENS_EXTRA; index++) {
-        currentToken = (tokenDefinition_t *) PIC(&TOKENS_EXTRA[index]);
-        if (memcmp(currentToken->address, token->address, 20) == 0) {
-            strcpy((char *) token->ticker, (char *) currentToken->ticker);
-            token->decimals = currentToken->decimals;
-            break;
-        }
-    }
-    if (index < NUM_TOKENS_EXTRA) {
-        PRINTF("Descriptor whitelisted\n");
-    } else
+    error = check_signature_with_pubkey("ERC20 Token Info",
+                                        hash,
+                                        sizeof(hash),
+                                        LEDGER_SIGNATURE_PUBLIC_KEY,
+                                        sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
+#ifdef HAVE_LEDGER_PKI
+                                        CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META,
 #endif
-    {
-        CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1,
-                                                   LEDGER_SIGNATURE_PUBLIC_KEY,
-                                                   sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
-                                                   &tokenKey));
-        if (!cx_ecdsa_verify_no_throw(&tokenKey, hash, 32, workBuffer + offset, dataLength)) {
+                                        (uint8_t *) (workBuffer + offset),
+                                        dataLength);
+    if (error != CX_OK) {
+        PRINTF("Invalid token signature\n");
 #ifndef HAVE_BYPASS_SIGNATURES
-            PRINTF("Invalid token signature\n");
-            THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
 #endif
-        }
     }
 
     G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex;
     validate_current_asset_info();
-    U2BE_ENCODE(G_io_apdu_buffer, 1, APDU_RESPONSE_OK);
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 3);
+    *tx += 1;
+    return APDU_RESPONSE_OK;
 }
-
-#endif
diff --git a/src_features/provideNFTInformation/cmd_provideNFTInfo.c b/src_features/provideNFTInformation/cmd_provideNFTInfo.c
index 2b46d9d6e..46bcfc97e 100644
--- a/src_features/provideNFTInformation/cmd_provideNFTInfo.c
+++ b/src_features/provideNFTInformation/cmd_provideNFTInfo.c
@@ -9,6 +9,9 @@
 #include "network.h"
 #include "public_keys.h"
 #include "manage_asset_info.h"
+#ifdef HAVE_LEDGER_PKI
+#include "os_pki.h"
+#endif
 
 #define TYPE_SIZE        1
 #define VERSION_SIZE     1
@@ -39,77 +42,70 @@ typedef bool verificationAlgo(const cx_ecfp_public_key_t *,
                               unsigned char *,
                               unsigned int);
 
-void handleProvideNFTInformation(uint8_t p1,
-                                 uint8_t p2,
-                                 const uint8_t *workBuffer,
-                                 uint8_t dataLength,
-                                 unsigned int *flags,
-                                 unsigned int *tx) {
-    UNUSED(p1);
-    UNUSED(p2);
-    UNUSED(tx);
-    UNUSED(flags);
+uint16_t handleProvideNFTInformation(const uint8_t *workBuffer,
+                                     uint8_t dataLength,
+                                     unsigned int *tx) {
     uint8_t hash[INT256_LENGTH];
-    cx_ecfp_public_key_t nftKey;
+    nftInfo_t *nft = NULL;
+    size_t offset = 0;
+    size_t payloadSize = 0;
+    uint8_t collectionNameLength = 0;
+    uint64_t chain_id = 0;
+    uint8_t signatureLen = 0;
+    cx_err_t error = CX_INTERNAL_ERROR;
+#ifdef HAVE_NFT_STAGING_KEY
+    uint8_t valid_keyId = STAGING_NFT_METADATA_KEY;
+#else
+    uint8_t valid_keyId = PROD_NFT_METADATA_KEY;
+#endif
+
     PRINTF("In handle provide NFTInformation\n");
 
     if ((pluginType != ERC721) && (pluginType != ERC1155)) {
         PRINTF("NFT metadata provided without proper plugin loaded!\n");
-        THROW(0x6985);
+        return APDU_RESPONSE_CONDITION_NOT_SATISFIED;
     }
-    nftInfo_t *nft = &get_current_asset_info()->nft;
+    nft = &get_current_asset_info()->nft;
 
     PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex);
 
-    size_t offset = 0;
-
     if (dataLength <= HEADER_SIZE) {
         PRINTF("Data too small for headers: expected at least %d, got %d\n",
                HEADER_SIZE,
                dataLength);
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
-    uint8_t type = workBuffer[offset];
-    switch (type) {
-        case TYPE_1:
-            break;
-        default:
-            PRINTF("Unsupported type %d\n", type);
-            THROW(APDU_RESPONSE_INVALID_DATA);
-            break;
+    if (workBuffer[offset] != TYPE_1) {
+        PRINTF("Unsupported type %d\n", workBuffer[offset]);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += TYPE_SIZE;
 
-    uint8_t version = workBuffer[offset];
-    switch (version) {
-        case VERSION_1:
-            break;
-        default:
-            PRINTF("Unsupported version %d\n", version);
-            THROW(APDU_RESPONSE_INVALID_DATA);
-            break;
+    if (workBuffer[offset] != VERSION_1) {
+        PRINTF("Unsupported version %d\n", workBuffer[offset]);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += VERSION_SIZE;
 
-    uint8_t collectionNameLength = workBuffer[offset];
+    collectionNameLength = workBuffer[offset];
     offset += NAME_LENGTH_SIZE;
 
     // Size of the payload (everything except the signature)
-    size_t payloadSize = HEADER_SIZE + collectionNameLength + ADDRESS_LENGTH + CHAIN_ID_SIZE +
-                         KEY_ID_SIZE + ALGORITHM_ID_SIZE;
+    payloadSize = HEADER_SIZE + collectionNameLength + ADDRESS_LENGTH + CHAIN_ID_SIZE +
+                  KEY_ID_SIZE + ALGORITHM_ID_SIZE;
     if (dataLength < payloadSize) {
         PRINTF("Data too small for payload: expected at least %d, got %d\n",
                payloadSize,
                dataLength);
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     if (collectionNameLength > COLLECTION_NAME_MAX_LEN) {
         PRINTF("CollectionName too big: expected max %d, got %d\n",
                COLLECTION_NAME_MAX_LEN,
                collectionNameLength);
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     // Safe because we've checked the size before.
@@ -124,85 +120,72 @@ void handleProvideNFTInformation(uint8_t p1,
     PRINTF("Address: %.*H\n", ADDRESS_LENGTH, workBuffer + offset);
     offset += ADDRESS_LENGTH;
 
-    uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
+    chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
     // this prints raw data, so to have a more meaningful print, display
     // the buffer before the endianness swap
     PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset));
     if (!app_compatible_with_chain_id(&chain_id)) {
         UNSUPPORTED_CHAIN_ID_MSG(chain_id);
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += CHAIN_ID_SIZE;
 
-    uint8_t keyId = workBuffer[offset];
-    const uint8_t *rawKey;
-    uint8_t rawKeyLen;
-
-    PRINTF("KeyID: %d\n", keyId);
-    switch (keyId) {
-#ifdef HAVE_NFT_STAGING_KEY
-        case STAGING_NFT_METADATA_KEY:
-#endif
-        case PROD_NFT_METADATA_KEY:
-            rawKey = LEDGER_NFT_METADATA_PUBLIC_KEY;
-            rawKeyLen = sizeof(LEDGER_NFT_METADATA_PUBLIC_KEY);
-            break;
-        default:
-            PRINTF("KeyID %d not supported\n", keyId);
-            THROW(APDU_RESPONSE_INVALID_DATA);
-            break;
+    if (workBuffer[offset] != valid_keyId) {
+        PRINTF("Unsupported KeyID %d\n", workBuffer[offset]);
+        return APDU_RESPONSE_INVALID_DATA;
     }
-    PRINTF("RawKey: %.*H\n", rawKeyLen, rawKey);
     offset += KEY_ID_SIZE;
 
-    uint8_t algorithmId = workBuffer[offset];
-    PRINTF("Algorithm: %d\n", algorithmId);
-
-    if (algorithmId != ALGORITHM_ID_1) {
-        PRINTF("Incorrect algorithmId %d\n", algorithmId);
-        THROW(APDU_RESPONSE_INVALID_DATA);
+    if (workBuffer[offset] != ALGORITHM_ID_1) {
+        PRINTF("Incorrect algorithmId %d\n", workBuffer[offset]);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += ALGORITHM_ID_SIZE;
+
     PRINTF("hashing: %.*H\n", payloadSize, workBuffer);
     cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash));
 
     if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE) {
         PRINTF("Data too short to hold signature length\n");
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
-    uint8_t signatureLen = workBuffer[offset];
+    signatureLen = workBuffer[offset];
     PRINTF("Signature len: %d\n", signatureLen);
     if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) {
         PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n",
                MIN_DER_SIG_SIZE,
                MAX_DER_SIG_SIZE,
                signatureLen);
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += SIGNATURE_LENGTH_SIZE;
 
     if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE + signatureLen) {
         PRINTF("Signature could not fit in data\n");
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
-    CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, rawKey, rawKeyLen, &nftKey));
-    if (!cx_ecdsa_verify_no_throw(&nftKey,
-                                  hash,
-                                  sizeof(hash),
-                                  (uint8_t *) workBuffer + offset,
-                                  signatureLen)) {
-#ifndef HAVE_BYPASS_SIGNATURES
-        PRINTF("Invalid NFT signature\n");
-        THROW(APDU_RESPONSE_INVALID_DATA);
+    error = check_signature_with_pubkey("NFT Info",
+                                        hash,
+                                        sizeof(hash),
+                                        LEDGER_NFT_METADATA_PUBLIC_KEY,
+                                        sizeof(LEDGER_NFT_METADATA_PUBLIC_KEY),
+#ifdef HAVE_LEDGER_PKI
+                                        CERTIFICATE_PUBLIC_KEY_USAGE_NFT_METADATA,
 #endif
+                                        (uint8_t *) (workBuffer + offset),
+                                        signatureLen);
+#ifndef HAVE_BYPASS_SIGNATURES
+    if (error != CX_OK) {
+        return APDU_RESPONSE_INVALID_DATA;
     }
+#endif
 
     G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex;
     validate_current_asset_info();
-    U2BE_ENCODE(G_io_apdu_buffer, 1, APDU_RESPONSE_OK);
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 3);
+    *tx += 1;
+    return APDU_RESPONSE_OK;
 }
 
 #endif  // HAVE_NFT_SUPPORT
diff --git a/src_features/provideTrustedName/cmd_provide_trusted_name.c b/src_features/provideTrustedName/cmd_provide_trusted_name.c
new file mode 100644
index 000000000..f8dcabc92
--- /dev/null
+++ b/src_features/provideTrustedName/cmd_provide_trusted_name.c
@@ -0,0 +1,947 @@
+#ifdef HAVE_TRUSTED_NAME
+
+#include <os.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include "common_utils.h"  // ARRAY_SIZE
+#include "apdu_constants.h"
+#include "trusted_name.h"
+#include "challenge.h"
+#include "mem.h"
+#include "hash_bytes.h"
+#include "network.h"
+#include "public_keys.h"
+#ifdef HAVE_LEDGER_PKI
+#include "os_pki.h"
+#endif
+
+#define P1_FIRST_CHUNK     0x01
+#define P1_FOLLOWING_CHUNK 0x00
+
+#define STRUCT_TYPE_TRUSTED_NAME 0x03
+#define ALGO_SECP256K1           1
+
+#define SLIP_44_ETHEREUM 60
+
+#define DER_LONG_FORM_FLAG        0x80  // 8th bit set
+#define DER_FIRST_BYTE_VALUE_MASK 0x7f
+
+typedef enum { TLV_TAG, TLV_LENGTH, TLV_VALUE } e_tlv_step;
+
+// This enum needs to be ordered the same way as the e_tlv_tag one !
+typedef enum {
+    STRUCT_TYPE_RCV_BIT = 0,
+    STRUCT_VERSION_RCV_BIT,
+    NOT_VALID_AFTER_RCV_BIT,
+    CHALLENGE_RCV_BIT,
+    SIGNER_KEY_ID_RCV_BIT,
+    SIGNER_ALGO_RCV_BIT,
+    SIGNATURE_RCV_BIT,
+    TRUSTED_NAME_RCV_BIT,
+    COIN_TYPE_RCV_BIT,
+    ADDRESS_RCV_BIT,
+    CHAIN_ID_RCV_BIT,
+    TRUSTED_NAME_TYPE_RCV_BIT,
+    TRUSTED_NAME_SOURCE_RCV_BIT,
+    NFT_ID_RCV_BIT,
+} e_tlv_rcv_bit;
+
+#define RCV_FLAG(a) (1 << a)
+
+typedef enum {
+    STRUCT_TYPE = 0x01,
+    STRUCT_VERSION = 0x02,
+    NOT_VALID_AFTER = 0x10,
+    CHALLENGE = 0x12,
+    SIGNER_KEY_ID = 0x13,
+    SIGNER_ALGO = 0x14,
+    SIGNATURE = 0x15,
+    TRUSTED_NAME = 0x20,
+    COIN_TYPE = 0x21,
+    ADDRESS = 0x22,
+    CHAIN_ID = 0x23,
+    TRUSTED_NAME_TYPE = 0x70,
+    TRUSTED_NAME_SOURCE = 0x71,
+    NFT_ID = 0x72,
+} e_tlv_tag;
+
+typedef enum { KEY_ID_TEST = 0x00, KEY_ID_PROD = 0x03 } e_key_id;
+
+typedef struct {
+    uint8_t *buf;
+    uint16_t size;
+    uint16_t expected_size;
+} s_tlv_payload;
+
+typedef struct {
+    e_tlv_tag tag;
+    uint8_t length;
+    const uint8_t *value;
+} s_tlv_data;
+
+typedef struct {
+    uint32_t rcv_flags;
+    bool valid;
+    uint8_t struct_version;
+    char *name;
+    uint8_t addr[ADDRESS_LENGTH];
+    uint64_t chain_id;
+    e_name_type name_type;
+    e_name_source name_source;
+    uint8_t nft_id[INT256_LENGTH];
+} s_trusted_name_info;
+
+typedef struct {
+    e_key_id key_id;
+    uint8_t input_sig_size;
+    const uint8_t *input_sig;
+    cx_sha256_t hash_ctx;
+} s_sig_ctx;
+
+typedef bool(t_tlv_handler)(const s_tlv_data *data,
+                            s_trusted_name_info *trusted_name_info,
+                            s_sig_ctx *sig_ctx);
+
+typedef struct {
+    e_tlv_tag tag;
+    t_tlv_handler *func;
+    e_tlv_rcv_bit rcv_bit;
+} s_tlv_handler;
+
+static s_tlv_payload g_tlv_payload = {0};
+static s_trusted_name_info g_trusted_name_info = {0};
+char g_trusted_name[TRUSTED_NAME_MAX_LENGTH + 1];
+
+/**
+ * Checks if a trusted name matches the given parameters
+ *
+ * Does not care about the trusted name source for now.
+ * Always wipes the content of \ref g_trusted_name_info
+ *
+ * @param[in] types_count number of given trusted name types
+ * @param[in] types given trusted name types
+ * @param[in] chain_id given chain ID
+ * @param[in] addr given address
+ * @return whether there is or not
+ */
+bool has_trusted_name(uint8_t types_count,
+                      const e_name_type *types,
+                      const uint64_t *chain_id,
+                      const uint8_t *addr) {
+    bool ret = false;
+
+    if (g_trusted_name_info.rcv_flags != 0) {
+        for (int i = 0; i < types_count; ++i) {
+            switch (g_trusted_name_info.struct_version) {
+                case 1:
+                    if (types[i] == TYPE_ACCOUNT) {
+                        // Check if chain ID is known to be Ethereum-compatible (same derivation
+                        // path)
+                        if ((chain_is_ethereum_compatible(chain_id)) &&
+                            (memcmp(addr, g_trusted_name_info.addr, ADDRESS_LENGTH) == 0)) {
+                            ret = true;
+                        }
+                    }
+                    break;
+                case 2:
+                    if (types[i] == g_trusted_name_info.name_type) {
+                        if (*chain_id == g_trusted_name_info.chain_id) {
+                            ret = true;
+                        }
+                    }
+                    break;
+                default:
+                    ret = false;
+            }
+            if (ret) break;
+        }
+        explicit_bzero(&g_trusted_name_info, sizeof(g_trusted_name_info));
+    }
+    return ret;
+}
+
+/**
+ * Get uint from tlv data
+ *
+ * Get an unsigned integer from variable length tlv data (up to 4 bytes)
+ *
+ * @param[in] data tlv data
+ * @param[out] value the returned value
+ * @return whether it was successful
+ */
+static bool get_uint_from_data(const s_tlv_data *data, uint32_t *value) {
+    uint8_t size_diff;
+    uint8_t buffer[sizeof(uint32_t)];
+
+    if (data->length > sizeof(buffer)) {
+        PRINTF("Unexpectedly long value (%u bytes) for tag 0x%x\n", data->length, data->tag);
+        return false;
+    }
+    size_diff = sizeof(buffer) - data->length;
+    memset(buffer, 0, size_diff);
+    memcpy(buffer + size_diff, data->value, data->length);
+    *value = U4BE(buffer, 0);
+    return true;
+}
+
+/**
+ * Handler for tag \ref STRUCT_TYPE
+ *
+ * @param[in] data the tlv data
+ * @param[] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_struct_type(const s_tlv_data *data,
+                               s_trusted_name_info *trusted_name_info,
+                               s_sig_ctx *sig_ctx) {
+    uint32_t value;
+
+    (void) trusted_name_info;
+    (void) sig_ctx;
+    if (!get_uint_from_data(data, &value)) {
+        return false;
+    }
+    return (value == STRUCT_TYPE_TRUSTED_NAME);
+}
+
+/**
+ * Handler for tag \ref NOT_VALID_AFTER
+ *
+ * @param[in] data the tlv data
+ * @param[] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_not_valid_after(const s_tlv_data *data,
+                                   s_trusted_name_info *trusted_name_info,
+                                   s_sig_ctx *sig_ctx) {
+    const uint8_t app_version[] = {MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION};
+    int i = 0;
+
+    (void) trusted_name_info;
+    (void) sig_ctx;
+    if (data->length != ARRAYLEN(app_version)) {
+        return false;
+    }
+    do {
+        if (data->value[i] < app_version[i]) {
+            PRINTF("Expired trusted name : %u.%u.%u < %u.%u.%u\n",
+                   data->value[0],
+                   data->value[1],
+                   data->value[2],
+                   app_version[0],
+                   app_version[1],
+                   app_version[2]);
+            return false;
+        }
+        i += 1;
+    } while ((i < (int) ARRAYLEN(app_version)) && (data->value[i] == app_version[i]));
+    return true;
+}
+
+/**
+ * Handler for tag \ref STRUCT_VERSION
+ *
+ * @param[in] data the tlv data
+ * @param[out] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_struct_version(const s_tlv_data *data,
+                                  s_trusted_name_info *trusted_name_info,
+                                  s_sig_ctx *sig_ctx) {
+    uint32_t value;
+
+    (void) sig_ctx;
+    if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) {
+        return false;
+    }
+    trusted_name_info->struct_version = value;
+    return true;
+}
+
+/**
+ * Handler for tag \ref CHALLENGE
+ *
+ * @param[in] data the tlv data
+ * @param[] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_challenge(const s_tlv_data *data,
+                             s_trusted_name_info *trusted_name_info,
+                             s_sig_ctx *sig_ctx) {
+    uint32_t value;
+    (void) trusted_name_info;
+    (void) sig_ctx;
+
+    if (!get_uint_from_data(data, &value)) {
+        return false;
+    }
+    return (value == get_challenge());
+}
+
+/**
+ * Handler for tag \ref SIGNER_KEY_ID
+ *
+ * @param[in] data the tlv data
+ * @param[] trusted_name_info the trusted name information
+ * @param[out] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_sign_key_id(const s_tlv_data *data,
+                               s_trusted_name_info *trusted_name_info,
+                               s_sig_ctx *sig_ctx) {
+    uint32_t value;
+    (void) trusted_name_info;
+
+    if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) {
+        return false;
+    }
+    sig_ctx->key_id = value;
+    return true;
+}
+
+/**
+ * Handler for tag \ref SIGNER_ALGO
+ *
+ * @param[in] data the tlv data
+ * @param[] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_sign_algo(const s_tlv_data *data,
+                             s_trusted_name_info *trusted_name_info,
+                             s_sig_ctx *sig_ctx) {
+    uint32_t value;
+
+    (void) trusted_name_info;
+    (void) sig_ctx;
+    if (!get_uint_from_data(data, &value)) {
+        return false;
+    }
+    return (value == ALGO_SECP256K1);
+}
+
+/**
+ * Handler for tag \ref SIGNATURE
+ *
+ * @param[in] data the tlv data
+ * @param[] trusted_name_info the trusted name information
+ * @param[out] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_signature(const s_tlv_data *data,
+                             s_trusted_name_info *trusted_name_info,
+                             s_sig_ctx *sig_ctx) {
+    (void) trusted_name_info;
+    sig_ctx->input_sig_size = data->length;
+    sig_ctx->input_sig = data->value;
+    return true;
+}
+
+/**
+ * Tests if the given account name character is valid (in our subset of allowed characters)
+ *
+ * @param[in] c given character
+ * @return whether the character is valid
+ */
+static bool is_valid_account_character(char c) {
+    if (isalpha((int) c)) {
+        if (!islower((int) c)) {
+            return false;
+        }
+    } else if (!isdigit((int) c)) {
+        switch (c) {
+            case '.':
+            case '-':
+            case '_':
+                break;
+            default:
+                return false;
+        }
+    }
+    return true;
+}
+
+/**
+ * Handler for tag \ref TRUSTED_NAME
+ *
+ * @param[in] data the tlv data
+ * @param[out] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_trusted_name(const s_tlv_data *data,
+                                s_trusted_name_info *trusted_name_info,
+                                s_sig_ctx *sig_ctx) {
+    (void) sig_ctx;
+    if (data->length > TRUSTED_NAME_MAX_LENGTH) {
+        PRINTF("Domain name too long! (%u)\n", data->length);
+        return false;
+    }
+    if ((trusted_name_info->struct_version == 1) ||
+        (trusted_name_info->name_type == TYPE_ACCOUNT)) {
+        // TODO: Remove once other domain name providers are supported
+        if ((data->length < 5) ||
+            (strncmp(".eth", (char *) &data->value[data->length - 4], 4) != 0)) {
+            PRINTF("Unexpected TLD!\n");
+            return false;
+        }
+        for (int idx = 0; idx < data->length; ++idx) {
+            if (!is_valid_account_character(data->value[idx])) {
+                PRINTF("Domain name contains non-allowed character! (0x%x)\n", data->value[idx]);
+                return false;
+            }
+            trusted_name_info->name[idx] = data->value[idx];
+        }
+    } else {
+        memcpy(trusted_name_info->name, data->value, data->length);
+    }
+    trusted_name_info->name[data->length] = '\0';
+    return true;
+}
+
+/**
+ * Handler for tag \ref COIN_TYPE
+ *
+ * @param[in] data the tlv data
+ * @param[] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_coin_type(const s_tlv_data *data,
+                             s_trusted_name_info *trusted_name_info,
+                             s_sig_ctx *sig_ctx) {
+    uint32_t value;
+
+    (void) trusted_name_info;
+    (void) sig_ctx;
+    if (!get_uint_from_data(data, &value)) {
+        return false;
+    }
+    return (value == SLIP_44_ETHEREUM);
+}
+
+/**
+ * Handler for tag \ref ADDRESS
+ *
+ * @param[in] data the tlv data
+ * @param[out] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_address(const s_tlv_data *data,
+                           s_trusted_name_info *trusted_name_info,
+                           s_sig_ctx *sig_ctx) {
+    (void) sig_ctx;
+    if (data->length != ADDRESS_LENGTH) {
+        return false;
+    }
+    memcpy(trusted_name_info->addr, data->value, ADDRESS_LENGTH);
+    return true;
+}
+
+/**
+ * Handler for tag \ref CHAIN_ID
+ *
+ * @param[in] data the tlv data
+ * @param[out] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_chain_id(const s_tlv_data *data,
+                            s_trusted_name_info *trusted_name_info,
+                            s_sig_ctx *sig_ctx) {
+    (void) sig_ctx;
+    trusted_name_info->chain_id = u64_from_BE(data->value, data->length);
+    return true;
+}
+
+/**
+ * Handler for tag \ref TRUSTED_NAME_TYPE
+ *
+ * @param[in] data the tlv data
+ * @param[out] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_trusted_name_type(const s_tlv_data *data,
+                                     s_trusted_name_info *trusted_name_info,
+                                     s_sig_ctx *sig_ctx) {
+    uint32_t value;
+
+    (void) trusted_name_info;
+    (void) sig_ctx;
+    if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) {
+        return false;
+    }
+    switch (value) {
+        case TYPE_ACCOUNT:
+        case TYPE_CONTRACT:
+            break;
+        case TYPE_NFT:
+        default:
+            PRINTF("Error: unsupported trusted name type (%u)!\n", value);
+            return false;
+    }
+    trusted_name_info->name_type = value;
+    return true;
+}
+
+/**
+ * Handler for tag \ref TRUSTED_NAME_SOURCE
+ *
+ * @param[in] data the tlv data
+ * @param[out] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_trusted_name_source(const s_tlv_data *data,
+                                       s_trusted_name_info *trusted_name_info,
+                                       s_sig_ctx *sig_ctx) {
+    uint32_t value;
+
+    (void) trusted_name_info;
+    (void) sig_ctx;
+    if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) {
+        return false;
+    }
+    switch (value) {
+        case SOURCE_CAL:
+        case SOURCE_ENS:
+            break;
+        case SOURCE_LAB:
+        case SOURCE_UD:
+        case SOURCE_FN:
+        case SOURCE_DNS:
+        default:
+            PRINTF("Error: unsupported trusted name source (%u)!\n", value);
+            return false;
+    }
+    trusted_name_info->name_source = value;
+    return true;
+}
+
+/**
+ * Handler for tag \ref NFT_ID
+ *
+ * @param[in] data the tlv data
+ * @param[out] trusted_name_info the trusted name information
+ * @param[] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_nft_id(const s_tlv_data *data,
+                          s_trusted_name_info *trusted_name_info,
+                          s_sig_ctx *sig_ctx) {
+    size_t diff;
+
+    (void) trusted_name_info;
+    (void) sig_ctx;
+    if (data->length > sizeof(trusted_name_info->nft_id)) {
+        return false;
+    }
+    diff = sizeof(trusted_name_info->nft_id) - data->length;
+    memmove(trusted_name_info->nft_id + diff, data->value, data->length);
+    explicit_bzero(trusted_name_info->nft_id, diff);
+    return true;  // unhandled for now
+}
+
+/**
+ * Verify the signature context
+ *
+ * Verify the SHA-256 hash of the payload against the public key
+ *
+ * @param[in] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool verify_signature(const s_sig_ctx *sig_ctx) {
+    uint8_t hash[INT256_LENGTH];
+    cx_err_t error = CX_INTERNAL_ERROR;
+#ifdef HAVE_TRUSTED_NAME_TEST_KEY
+    e_key_id valid_key_id = KEY_ID_TEST;
+#else
+    e_key_id valid_key_id = KEY_ID_PROD;
+#endif
+    bool ret_code = false;
+
+    if (sig_ctx->key_id != valid_key_id) {
+        PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id);
+        return false;
+    }
+
+    CX_CHECK(
+        cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH));
+
+    CX_CHECK(check_signature_with_pubkey("Domain Name",
+                                         hash,
+                                         sizeof(hash),
+                                         TRUSTED_NAME_PUB_KEY,
+                                         sizeof(TRUSTED_NAME_PUB_KEY),
+#ifdef HAVE_LEDGER_PKI
+                                         CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META,
+#endif
+                                         (uint8_t *) (sig_ctx->input_sig),
+                                         sig_ctx->input_sig_size));
+
+    ret_code = true;
+end:
+    return ret_code;
+}
+
+/**
+ * Calls the proper handler for the given TLV data
+ *
+ * Checks if there is a proper handler function for the given TLV tag and then calls it
+ *
+ * @param[in] handlers list of tag / handler function pairs
+ * @param[in] handler_count number of handlers
+ * @param[in] data the TLV data
+ * @param[out] trusted_name_info the trusted name information
+ * @param[out] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool handle_tlv_data(s_tlv_handler *handlers,
+                            int handler_count,
+                            const s_tlv_data *data,
+                            s_trusted_name_info *trusted_name_info,
+                            s_sig_ctx *sig_ctx) {
+    t_tlv_handler *fptr;
+
+    // check if a handler exists for this tag
+    for (int idx = 0; idx < handler_count; ++idx) {
+        if (handlers[idx].tag == data->tag) {
+            trusted_name_info->rcv_flags |= RCV_FLAG(handlers[idx].rcv_bit);
+            fptr = PIC(handlers[idx].func);
+            if (!(*fptr)(data, trusted_name_info, sig_ctx)) {
+                PRINTF("Error while handling tag 0x%x\n", handlers[idx].tag);
+                return false;
+            }
+            break;
+        }
+    }
+    return true;
+}
+
+/**
+ * Verify the validity of the received trusted struct
+ *
+ * @param[in] trusted_name_info the trusted name information
+ * @return whether the struct is valid
+ */
+static bool verify_struct(const s_trusted_name_info *trusted_name_info) {
+    uint32_t required_flags;
+
+    if (!(RCV_FLAG(STRUCT_VERSION_RCV_BIT) & trusted_name_info->rcv_flags)) {
+        PRINTF("Error: no struct version specified!\n");
+        return false;
+    }
+    required_flags = RCV_FLAG(STRUCT_TYPE_RCV_BIT) | RCV_FLAG(STRUCT_VERSION_RCV_BIT) |
+                     RCV_FLAG(SIGNER_KEY_ID_RCV_BIT) | RCV_FLAG(SIGNER_ALGO_RCV_BIT) |
+                     RCV_FLAG(SIGNATURE_RCV_BIT) | RCV_FLAG(TRUSTED_NAME_RCV_BIT) |
+                     RCV_FLAG(ADDRESS_RCV_BIT);
+    switch (trusted_name_info->struct_version) {
+        case 1:
+            required_flags |= RCV_FLAG(CHALLENGE_RCV_BIT) | RCV_FLAG(COIN_TYPE_RCV_BIT);
+            if ((trusted_name_info->rcv_flags & required_flags) != required_flags) {
+                return false;
+            }
+            break;
+        case 2:
+            required_flags |= RCV_FLAG(CHAIN_ID_RCV_BIT) | RCV_FLAG(TRUSTED_NAME_TYPE_RCV_BIT) |
+                              RCV_FLAG(TRUSTED_NAME_SOURCE_RCV_BIT);
+            if ((trusted_name_info->rcv_flags & required_flags) != required_flags) {
+                return false;
+            }
+            switch (trusted_name_info->name_type) {
+                case TYPE_ACCOUNT:
+                    if (trusted_name_info->name_source == SOURCE_CAL) {
+                        PRINTF("Error: cannot accept an account name from the CAL!\n");
+                        return false;
+                    }
+                    if (!(trusted_name_info->rcv_flags & RCV_FLAG(CHALLENGE_RCV_BIT))) {
+                        PRINTF("Error: trusted account name requires a challenge!\n");
+                        return false;
+                    }
+                    break;
+                case TYPE_CONTRACT:
+                    if (trusted_name_info->name_source != SOURCE_CAL) {
+                        PRINTF("Error: cannot accept a contract name from given source (%u)!\n",
+                               trusted_name_info->name_source);
+                        return false;
+                    }
+                    break;
+                default:
+                    return false;
+            }
+            break;
+        default:
+            PRINTF("Error: unsupported trusted name struct version (%u) !\n",
+                   trusted_name_info->struct_version);
+            return false;
+    }
+    return true;
+}
+
+/** Parse DER-encoded value
+ *
+ * Parses a DER-encoded value (up to 4 bytes long)
+ * https://en.wikipedia.org/wiki/X.690
+ *
+ * @param[in] payload the TLV payload
+ * @param[in,out] offset the payload offset
+ * @param[out] value the parsed value
+ * @return whether it was successful
+ */
+static bool parse_der_value(const s_tlv_payload *payload, size_t *offset, uint32_t *value) {
+    bool ret = false;
+    uint8_t byte_length;
+    uint8_t buf[sizeof(*value)];
+
+    if (value != NULL) {
+        if (payload->buf[*offset] & DER_LONG_FORM_FLAG) {  // long form
+            byte_length = payload->buf[*offset] & DER_FIRST_BYTE_VALUE_MASK;
+            *offset += 1;
+            if ((*offset + byte_length) > payload->size) {
+                PRINTF("TLV payload too small for DER encoded value\n");
+            } else {
+                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));
+                    memcpy(buf + (sizeof(buf) - byte_length), &payload->buf[*offset], byte_length);
+                    *value = U4BE(buf, 0);
+                    *offset += byte_length;
+                    ret = true;
+                }
+            }
+        } else {  // short form
+            *value = payload->buf[*offset];
+            *offset += 1;
+            ret = true;
+        }
+    }
+    return ret;
+}
+
+/**
+ * Get DER-encoded value as an uint8
+ *
+ * Parses the value and checks if it fits in the given \ref uint8_t value
+ *
+ * @param[in] payload the TLV payload
+ * @param[in,out] offset
+ * @param[out] value the parsed value
+ * @return whether it was successful
+ */
+static bool get_der_value_as_uint8(const s_tlv_payload *payload, size_t *offset, uint8_t *value) {
+    bool ret = false;
+    uint32_t tmp_value;
+
+    if (value != NULL) {
+        if (!parse_der_value(payload, offset, &tmp_value)) {
+        } else {
+            if (tmp_value <= UINT8_MAX) {
+                *value = tmp_value;
+                ret = true;
+            } else {
+                PRINTF("TLV DER-encoded value larger than 8 bits\n");
+            }
+        }
+    }
+    return ret;
+}
+
+/**
+ * Parse the TLV payload
+ *
+ * Does the TLV parsing but also the SHA-256 hash of the payload.
+ *
+ * @param[in] payload the raw TLV payload
+ * @param[out] trusted_name_info the trusted name information
+ * @param[out] sig_ctx the signature context
+ * @return whether it was successful
+ */
+static bool parse_tlv(const s_tlv_payload *payload,
+                      s_trusted_name_info *trusted_name_info,
+                      s_sig_ctx *sig_ctx) {
+    s_tlv_handler handlers[] = {
+        {.tag = STRUCT_TYPE, .func = &handle_struct_type},
+        {.tag = STRUCT_VERSION, .func = &handle_struct_version},
+        {.tag = NOT_VALID_AFTER, .func = &handle_not_valid_after},
+        {.tag = CHALLENGE, .func = &handle_challenge},
+        {.tag = SIGNER_KEY_ID, .func = &handle_sign_key_id},
+        {.tag = SIGNER_ALGO, .func = &handle_sign_algo},
+        {.tag = SIGNATURE, .func = &handle_signature},
+        {.tag = TRUSTED_NAME, .func = &handle_trusted_name},
+        {.tag = COIN_TYPE, .func = &handle_coin_type},
+        {.tag = ADDRESS, .func = &handle_address},
+        {.tag = CHAIN_ID, .func = &handle_chain_id},
+        {.tag = TRUSTED_NAME_TYPE, .func = &handle_trusted_name_type},
+        {.tag = TRUSTED_NAME_SOURCE, .func = &handle_trusted_name_source},
+        {.tag = NFT_ID, .func = &handle_nft_id},
+    };
+    e_tlv_step step = TLV_TAG;
+    s_tlv_data data;
+    size_t offset = 0;
+    size_t tag_start_off;
+
+    for (size_t i = 0; i < ARRAYLEN(handlers); ++i) handlers[i].rcv_bit = i;
+    cx_sha256_init(&sig_ctx->hash_ctx);
+    // handle TLV payload
+    while (offset < payload->size) {
+        switch (step) {
+            case TLV_TAG:
+                tag_start_off = offset;
+                if (!get_der_value_as_uint8(payload, &offset, &data.tag)) {
+                    return false;
+                }
+                step = TLV_LENGTH;
+                break;
+
+            case TLV_LENGTH:
+                if (!get_der_value_as_uint8(payload, &offset, &data.length)) {
+                    return false;
+                }
+                step = TLV_VALUE;
+                break;
+
+            case TLV_VALUE:
+                if ((offset + data.length) > payload->size) {
+                    PRINTF("Error: value would go beyond the TLV payload!\n");
+                    return false;
+                }
+                data.value = &payload->buf[offset];
+                if (!handle_tlv_data(handlers,
+                                     ARRAY_SIZE(handlers),
+                                     &data,
+                                     trusted_name_info,
+                                     sig_ctx)) {
+                    return false;
+                }
+                offset += data.length;
+                if (data.tag != SIGNATURE) {  // the signature wasn't computed on itself
+                    hash_nbytes(&payload->buf[tag_start_off],
+                                (offset - tag_start_off),
+                                (cx_hash_t *) &sig_ctx->hash_ctx);
+                }
+                step = TLV_TAG;
+                break;
+
+            default:
+                return false;
+        }
+    }
+    if (step != TLV_TAG) {
+        PRINTF("Error: unexpected data at the end of the TLV payload!\n");
+        return false;
+    }
+    return verify_struct(trusted_name_info);
+}
+
+/**
+ * Allocate and assign TLV payload
+ *
+ * @param[in] payload payload structure
+ * @param[in] size size of the payload
+ * @return whether it was successful
+ */
+static bool alloc_payload(s_tlv_payload *payload, uint16_t size) {
+    if ((payload->buf = mem_alloc(size)) == NULL) {
+        return false;
+    }
+    payload->expected_size = size;
+    return true;
+}
+
+/**
+ * Deallocate and unassign TLV payload
+ *
+ * @param[in] payload payload structure
+ */
+static void free_payload(s_tlv_payload *payload) {
+    mem_dealloc(payload->expected_size);
+    memset(payload, 0, sizeof(*payload));
+}
+
+static bool handle_first_chunk(const uint8_t **data,
+                               uint8_t *length,
+                               s_tlv_payload *payload,
+                               uint16_t *sw) {
+    // check if no payload is already in memory
+    if (payload->buf != NULL) {
+        free_payload(payload);
+        *sw = APDU_RESPONSE_INVALID_P1_P2;
+        return false;
+    }
+
+    // check if we at least get the size
+    if (*length < sizeof(payload->expected_size)) {
+        *sw = APDU_RESPONSE_INVALID_DATA;
+        return false;
+    }
+    if (!alloc_payload(payload, U2BE(*data, 0))) {
+        *sw = APDU_RESPONSE_INSUFFICIENT_MEMORY;
+        return false;
+    }
+
+    // skip the size so we can process it like a following chunk
+    *data += sizeof(payload->expected_size);
+    *length -= sizeof(payload->expected_size);
+    return true;
+}
+
+/**
+ * Handle trusted name APDU
+ *
+ * @param[in] p1 first APDU instruction parameter
+ * @param[in] data APDU payload
+ * @param[in] length payload size
+ */
+uint16_t handle_provide_trusted_name(uint8_t p1, const uint8_t *data, uint8_t length) {
+    s_sig_ctx sig_ctx;
+    uint16_t sw = APDU_NO_RESPONSE;
+
+    if (p1 == P1_FIRST_CHUNK) {
+        if (!handle_first_chunk(&data, &length, &g_tlv_payload, &sw)) {
+            return sw;
+        }
+    } else {
+        // check if a payload is already in memory
+        if (g_tlv_payload.buf == NULL) {
+            return APDU_RESPONSE_INVALID_P1_P2;
+        }
+    }
+
+    if ((g_tlv_payload.size + length) > g_tlv_payload.expected_size) {
+        free_payload(&g_tlv_payload);
+        PRINTF("TLV payload size mismatch!\n");
+        return APDU_RESPONSE_INVALID_DATA;
+    }
+    // feed into tlv payload
+    memcpy(g_tlv_payload.buf + g_tlv_payload.size, data, length);
+    g_tlv_payload.size += length;
+
+    // everything has been received
+    if (g_tlv_payload.size == g_tlv_payload.expected_size) {
+        g_trusted_name_info.name = g_trusted_name;
+        if (!parse_tlv(&g_tlv_payload, &g_trusted_name_info, &sig_ctx) ||
+            !verify_signature(&sig_ctx)) {
+            free_payload(&g_tlv_payload);
+            roll_challenge();  // prevent brute-force guesses
+            g_trusted_name_info.rcv_flags = 0;
+            return APDU_RESPONSE_INVALID_DATA;
+        }
+        PRINTF("Registered : %s => %.*h\n",
+               g_trusted_name_info.name,
+               ADDRESS_LENGTH,
+               g_trusted_name_info.addr);
+        free_payload(&g_tlv_payload);
+        roll_challenge();  // prevent replays
+    }
+    return APDU_RESPONSE_OK;
+}
+
+#endif  // HAVE_TRUSTED_NAME
diff --git a/src_features/provideTrustedName/trusted_name.h b/src_features/provideTrustedName/trusted_name.h
new file mode 100644
index 000000000..142a5b7b0
--- /dev/null
+++ b/src_features/provideTrustedName/trusted_name.h
@@ -0,0 +1,36 @@
+#ifdef HAVE_TRUSTED_NAME
+
+#ifndef TRUSTED_NAME_H_
+#define TRUSTED_NAME_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define TRUSTED_NAME_MAX_LENGTH 30
+
+typedef enum {
+    TYPE_ACCOUNT = 1,
+    TYPE_CONTRACT,
+    TYPE_NFT,
+} e_name_type;
+
+typedef enum {
+    SOURCE_LAB = 0,
+    SOURCE_CAL,
+    SOURCE_ENS,
+    SOURCE_UD,
+    SOURCE_FN,
+    SOURCE_DNS,
+} e_name_source;
+
+bool has_trusted_name(uint8_t types_count,
+                      const e_name_type *types,
+                      const uint64_t *chain_id,
+                      const uint8_t *addr);
+uint16_t handle_provide_trusted_name(uint8_t p1, const uint8_t *data, uint8_t length);
+
+extern char g_trusted_name[TRUSTED_NAME_MAX_LENGTH + 1];
+
+#endif  // TRUSTED_NAME_H_
+
+#endif  // HAVE_TRUSTED_NAME
diff --git a/src_features/setEth2WithdrawalIndex/cmd_setEth2WithdrawalIndex.c b/src_features/setEth2WithdrawalIndex/cmd_setEth2WithdrawalIndex.c
index a7f6f72b6..74337df34 100644
--- a/src_features/setEth2WithdrawalIndex/cmd_setEth2WithdrawalIndex.c
+++ b/src_features/setEth2WithdrawalIndex/cmd_setEth2WithdrawalIndex.c
@@ -3,23 +3,21 @@
 #include "shared_context.h"
 #include "apdu_constants.h"
 
-void handleSetEth2WithdrawalIndex(uint8_t p1,
-                                  uint8_t p2,
-                                  const uint8_t *dataBuffer,
-                                  uint16_t dataLength,
-                                  __attribute__((unused)) unsigned int *flags,
-                                  __attribute__((unused)) unsigned int *tx) {
+uint16_t handleSetEth2WithdrawalIndex(uint8_t p1,
+                                      uint8_t p2,
+                                      const uint8_t *dataBuffer,
+                                      uint16_t dataLength) {
     if (dataLength != 4) {
-        THROW(0x6700);
+        return APDU_RESPONSE_WRONG_DATA_LENGTH;
     }
 
     if ((p1 != 0) || (p2 != 0)) {
-        THROW(0x6B00);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
 
     eth2WithdrawalIndex = U4BE(dataBuffer, 0);
 
-    THROW(0x9000);
+    return APDU_RESPONSE_OK;
 }
 
 #endif
diff --git a/src_features/setEth2WithdrawalIndex/withdrawal_index.h b/src_features/setEth2WithdrawalIndex/withdrawal_index.h
index bf9d6a36f..ab8c9e554 100644
--- a/src_features/setEth2WithdrawalIndex/withdrawal_index.h
+++ b/src_features/setEth2WithdrawalIndex/withdrawal_index.h
@@ -3,11 +3,9 @@
 
 #include "stdint.h"
 
-void handleSetEth2WithdrawalIndex(uint8_t p1,
-                                  uint8_t p2,
-                                  uint8_t *dataBuffer,
-                                  uint16_t dataLength,
-                                  unsigned int *flags,
-                                  unsigned int *tx);
+uint16_t handleSetEth2WithdrawalIndex(uint8_t p1,
+                                      uint8_t p2,
+                                      uint8_t *dataBuffer,
+                                      uint16_t dataLength);
 
 #endif  // _SET_WITHDRAWAL_INDEX_H_
diff --git a/src_features/setExternalPlugin/cmd_setExternalPlugin.c b/src_features/setExternalPlugin/cmd_setExternalPlugin.c
index a2ddd71f2..6ab3b3915 100644
--- a/src_features/setExternalPlugin/cmd_setExternalPlugin.c
+++ b/src_features/setExternalPlugin/cmd_setExternalPlugin.c
@@ -6,51 +6,49 @@
 #include "plugin_utils.h"
 #include "common_ui.h"
 #include "os_io_seproxyhal.h"
+#ifdef HAVE_LEDGER_PKI
+#include "os_pki.h"
+#endif
 
-void handleSetExternalPlugin(uint8_t p1,
-                             uint8_t p2,
-                             const uint8_t *workBuffer,
-                             uint8_t dataLength,
-                             unsigned int *flags,
-                             unsigned int *tx) {
-    UNUSED(p1);
-    UNUSED(p2);
-    UNUSED(flags);
+uint16_t handleSetExternalPlugin(const uint8_t *workBuffer, uint8_t dataLength) {
     PRINTF("Handling set Plugin\n");
     uint8_t hash[INT256_LENGTH];
-    cx_ecfp_public_key_t tokenKey;
     uint8_t pluginNameLength = *workBuffer;
+    uint32_t params[2];
+    cx_err_t error = CX_INTERNAL_ERROR;
+
     PRINTF("plugin Name Length: %d\n", pluginNameLength);
     const size_t payload_size = 1 + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE;
 
     if (dataLength <= payload_size) {
         PRINTF("data too small: expected at least %d got %d\n", payload_size, dataLength);
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     if (pluginNameLength + 1 > sizeof(dataContext.tokenContext.pluginName)) {
         PRINTF("name length too big: expected max %d, got %d\n",
                sizeof(dataContext.tokenContext.pluginName),
                pluginNameLength + 1);
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     // check Ledger's signature over the payload
     cx_hash_sha256(workBuffer, payload_size, hash, sizeof(hash));
-    CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1,
-                                               LEDGER_SIGNATURE_PUBLIC_KEY,
-                                               sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
-                                               &tokenKey));
-    if (!cx_ecdsa_verify_no_throw(&tokenKey,
-                                  hash,
-                                  sizeof(hash),
-                                  workBuffer + payload_size,
-                                  dataLength - payload_size)) {
+
+    error = check_signature_with_pubkey("External Plugin",
+                                        hash,
+                                        sizeof(hash),
+                                        LEDGER_SIGNATURE_PUBLIC_KEY,
+                                        sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
+#ifdef HAVE_LEDGER_PKI
+                                        CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META,
+#endif
+                                        (uint8_t *) (workBuffer + payload_size),
+                                        dataLength - payload_size);
+    if (error != CX_OK) {
+        PRINTF("Invalid signature\n");
 #ifndef HAVE_BYPASS_SIGNATURES
-        PRINTF("Invalid plugin signature %.*H\n",
-               dataLength - payload_size,
-               workBuffer + payload_size);
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
 #endif
     }
 
@@ -63,7 +61,6 @@ void handleSetExternalPlugin(uint8_t p1,
     PRINTF("Check external plugin %s\n", dataContext.tokenContext.pluginName);
 
     // Check if the plugin is present on the device
-    uint32_t params[2];
     params[0] = (uint32_t) dataContext.tokenContext.pluginName;
     params[1] = ETH_PLUGIN_CHECK_PRESENCE;
     BEGIN_TRY {
@@ -75,7 +72,8 @@ void handleSetExternalPlugin(uint8_t p1,
             memset(dataContext.tokenContext.pluginName,
                    0,
                    sizeof(dataContext.tokenContext.pluginName));
-            THROW(0x6984);
+            CLOSE_TRY;
+            return APDU_RESPONSE_PLUGIN_NOT_INSTALLED;
         }
         FINALLY {
         }
@@ -83,13 +81,10 @@ void handleSetExternalPlugin(uint8_t p1,
     END_TRY;
 
     PRINTF("Plugin found\n");
-
     memmove(dataContext.tokenContext.contractAddress, workBuffer, ADDRESS_LENGTH);
     workBuffer += ADDRESS_LENGTH;
     memmove(dataContext.tokenContext.methodSelector, workBuffer, SELECTOR_SIZE);
-
     pluginType = EXTERNAL;
 
-    G_io_apdu_buffer[(*tx)++] = 0x90;
-    G_io_apdu_buffer[(*tx)++] = 0x00;
+    return APDU_RESPONSE_OK;
 }
diff --git a/src_features/setPlugin/cmd_setPlugin.c b/src_features/setPlugin/cmd_setPlugin.c
index d083d9b06..91455b4ce 100644
--- a/src_features/setPlugin/cmd_setPlugin.c
+++ b/src_features/setPlugin/cmd_setPlugin.c
@@ -9,6 +9,9 @@
 #include "os_io_seproxyhal.h"
 #include "network.h"
 #include "public_keys.h"
+#ifdef HAVE_LEDGER_PKI
+#include "os_pki.h"
+#endif
 
 // Supported internal plugins
 #define ERC721_STR  "ERC721"
@@ -62,73 +65,71 @@ typedef bool verificationAlgo(const cx_ecfp_public_key_t *,
 static pluginType_t getPluginType(char *pluginName, uint8_t pluginNameLength) {
     if (pluginNameLength == sizeof(ERC721_STR) - 1 &&
         strncmp(pluginName, ERC721_STR, pluginNameLength) == 0) {
+        PRINTF("Using internal plugin ERC721\n");
         return ERC721;
     } else if (pluginNameLength == sizeof(ERC1155_STR) - 1 &&
                strncmp(pluginName, ERC1155_STR, pluginNameLength) == 0) {
+        PRINTF("Using internal plugin ERC1155\n");
         return ERC1155;
     } else {
+        PRINTF("Using external plugin\n");
         return EXTERNAL;
     }
 }
 
-void handleSetPlugin(uint8_t p1,
-                     uint8_t p2,
-                     const uint8_t *workBuffer,
-                     uint8_t dataLength,
-                     unsigned int *flags,
-                     unsigned int *tx) {
-    UNUSED(p1);
-    UNUSED(p2);
-    UNUSED(flags);
+void set_swap_with_calldata_plugin_type(void) {
+    PRINTF("Using internal plugin SWAP_WITH_CALLDATA\n");
+    pluginType = SWAP_WITH_CALLDATA;
+}
+
+uint16_t handleSetPlugin(const uint8_t *workBuffer, uint8_t dataLength) {
     PRINTF("Handling set Plugin\n");
     uint8_t hash[INT256_LENGTH] = {0};
-    cx_ecfp_public_key_t pluginKey = {0};
     tokenContext_t *tokenContext = &dataContext.tokenContext;
-
     size_t offset = 0;
+    uint8_t pluginNameLength = 0;
+    size_t payloadSize = 0;
+    uint64_t chain_id = 0;
+    uint8_t signatureLen = 0;
+    cx_err_t error = CX_INTERNAL_ERROR;
+#ifdef HAVE_NFT_STAGING_KEY
+    enum KeyId valid_keyId = TEST_PLUGIN_KEY;
+#else
+    enum KeyId valid_keyId = PROD_PLUGIN_KEY;
+#endif
+    enum KeyId keyId;
+    uint32_t params[2];
 
     if (dataLength <= HEADER_SIZE) {
         PRINTF("Data too small for headers: expected at least %d, got %d\n",
                HEADER_SIZE,
                dataLength);
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
-    enum Type type = workBuffer[offset];
-    PRINTF("Type: %d\n", type);
-    switch (type) {
-        case ETH_PLUGIN:
-            break;
-        default:
-            PRINTF("Unsupported type %d\n", type);
-            THROW(0x6a80);
-            break;
+    if (workBuffer[offset] != ETH_PLUGIN) {
+        PRINTF("Unsupported type %d\n", workBuffer[offset]);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += TYPE_SIZE;
 
-    uint8_t version = workBuffer[offset];
-    PRINTF("version: %d\n", version);
-    switch (version) {
-        case VERSION_1:
-            break;
-        default:
-            PRINTF("Unsupported version %d\n", version);
-            THROW(0x6a80);
-            break;
+    if (workBuffer[offset] != VERSION_1) {
+        PRINTF("Unsupported version %d\n", workBuffer[offset]);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += VERSION_SIZE;
 
-    uint8_t pluginNameLength = workBuffer[offset];
+    pluginNameLength = workBuffer[offset];
     offset += PLUGIN_NAME_LENGTH_SIZE;
 
     // Size of the payload (everything except the signature)
-    size_t payloadSize = HEADER_SIZE + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE +
-                         CHAIN_ID_SIZE + KEY_ID_SIZE + ALGORITHM_ID_SIZE;
+    payloadSize = HEADER_SIZE + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE + CHAIN_ID_SIZE +
+                  KEY_ID_SIZE + ALGORITHM_ID_SIZE;
     if (dataLength < payloadSize) {
         PRINTF("Data too small for payload: expected at least %d, got %d\n",
                payloadSize,
                dataLength);
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     // `+ 1` because we want to add a null terminating character.
@@ -136,7 +137,7 @@ void handleSetPlugin(uint8_t p1,
         PRINTF("plugin name too big: expected max %d, got %d\n",
                sizeof(dataContext.tokenContext.pluginName),
                pluginNameLength + 1);
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
     // Safe because we've checked the size before.
@@ -155,79 +156,67 @@ void handleSetPlugin(uint8_t p1,
     PRINTF("Selector: %.*H\n", SELECTOR_SIZE, tokenContext->methodSelector);
     offset += SELECTOR_SIZE;
 
-    uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
+    chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
     // this prints raw data, so to have a more meaningful print, display
     // the buffer before the endianness swap
     PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset));
     if (!app_compatible_with_chain_id(&chain_id)) {
         UNSUPPORTED_CHAIN_ID_MSG(chain_id);
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += CHAIN_ID_SIZE;
 
-    enum KeyId keyId = workBuffer[offset];
-    uint8_t const *rawKey;
-    uint8_t rawKeyLen;
-
-    PRINTF("KeyID: %d\n", keyId);
-    switch (keyId) {
-#ifdef HAVE_NFT_STAGING_KEY
-        case TEST_PLUGIN_KEY:
-#endif
-        case PROD_PLUGIN_KEY:
-            rawKey = LEDGER_NFT_SELECTOR_PUBLIC_KEY;
-            rawKeyLen = sizeof(LEDGER_NFT_SELECTOR_PUBLIC_KEY);
-            break;
-        default:
-            PRINTF("KeyID %d not supported\n", keyId);
-            THROW(0x6A80);
-            break;
+    keyId = workBuffer[offset];
+    if (keyId != valid_keyId) {
+        PRINTF("Unsupported KeyID %d\n", keyId);
+        return APDU_RESPONSE_INVALID_DATA;
     }
-
-    PRINTF("RawKey: %.*H\n", rawKeyLen, rawKey);
     offset += KEY_ID_SIZE;
 
-    uint8_t algorithmId = workBuffer[offset];
-    PRINTF("Algorithm: %d\n", algorithmId);
-
-    if (algorithmId != ECC_SECG_P256K1__ECDSA_SHA_256) {
-        PRINTF("Incorrect algorithmId %d\n", algorithmId);
-        THROW(0x6a80);
+    if (workBuffer[offset] != ECC_SECG_P256K1__ECDSA_SHA_256) {
+        PRINTF("Incorrect algorithmId %d\n", workBuffer[offset]);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += ALGORITHM_ID_SIZE;
+
     PRINTF("hashing: %.*H\n", payloadSize, workBuffer);
     cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash));
 
     if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE) {
         PRINTF("Data too short to hold signature length\n");
-        THROW(0x6a80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
-    uint8_t signatureLen = workBuffer[offset];
+    signatureLen = workBuffer[offset];
     PRINTF("Signature len: %d\n", signatureLen);
     if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) {
         PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n",
                MIN_DER_SIG_SIZE,
                MAX_DER_SIG_SIZE,
                signatureLen);
-        THROW(0x6a80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     offset += SIGNATURE_LENGTH_SIZE;
 
     if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE + signatureLen) {
         PRINTF("Signature could not fit in data\n");
-        THROW(0x6a80);
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
-    CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, rawKey, rawKeyLen, &pluginKey));
-    if (!cx_ecdsa_verify_no_throw(&pluginKey,
-                                  hash,
-                                  sizeof(hash),
-                                  (unsigned char *) (workBuffer + offset),
-                                  signatureLen)) {
+    error = check_signature_with_pubkey("Set Plugin",
+                                        hash,
+                                        sizeof(hash),
+                                        LEDGER_NFT_SELECTOR_PUBLIC_KEY,
+                                        sizeof(LEDGER_NFT_SELECTOR_PUBLIC_KEY),
+#ifdef HAVE_LEDGER_PKI
+                                        CERTIFICATE_PUBLIC_KEY_USAGE_PLUGIN_METADATA,
+#endif
+                                        (uint8_t *) (workBuffer + offset),
+                                        signatureLen);
+    if (error != CX_OK) {
+        PRINTF("Invalid signature\n");
 #ifndef HAVE_BYPASS_SIGNATURES
-        PRINTF("Invalid NFT signature\n");
-        THROW(0x6A80);
+        return APDU_RESPONSE_INVALID_DATA;
 #endif
     }
 
@@ -235,37 +224,31 @@ void handleSetPlugin(uint8_t p1,
     if (keyId == PROD_PLUGIN_KEY) {
         if (pluginType != ERC721 && pluginType != ERC1155) {
             PRINTF("AWS key must only be used to set NFT internal plugins\n");
-            THROW(0x6A80);
+            return APDU_RESPONSE_INVALID_DATA;
         }
     }
 
-    switch (pluginType) {
-        case EXTERNAL: {
-            PRINTF("Check external plugin %s\n", tokenContext->pluginName);
-
-            // Check if the plugin is present on the device
-            uint32_t params[2];
-            params[0] = (uint32_t) tokenContext->pluginName;
-            params[1] = ETH_PLUGIN_CHECK_PRESENCE;
-            BEGIN_TRY {
-                TRY {
-                    os_lib_call(params);
-                }
-                CATCH_OTHER(e) {
-                    PRINTF("%s external plugin is not present\n", tokenContext->pluginName);
-                    memset(tokenContext->pluginName, 0, sizeof(tokenContext->pluginName));
-                    THROW(0x6984);
-                }
-                FINALLY {
-                }
+    if (pluginType == EXTERNAL) {
+        PRINTF("Check external plugin %s\n", tokenContext->pluginName);
+
+        // Check if the plugin is present on the device
+        params[0] = (uint32_t) tokenContext->pluginName;
+        params[1] = ETH_PLUGIN_CHECK_PRESENCE;
+        BEGIN_TRY {
+            TRY {
+                os_lib_call(params);
+            }
+            CATCH_OTHER(e) {
+                PRINTF("%s external plugin is not present\n", tokenContext->pluginName);
+                memset(tokenContext->pluginName, 0, sizeof(tokenContext->pluginName));
+                CLOSE_TRY;
+                return APDU_RESPONSE_PLUGIN_NOT_INSTALLED;
+            }
+            FINALLY {
             }
-            END_TRY;
-            break;
         }
-        default:
-            break;
+        END_TRY;
     }
 
-    G_io_apdu_buffer[(*tx)++] = 0x90;
-    G_io_apdu_buffer[(*tx)++] = 0x00;
+    return APDU_RESPONSE_OK;
 }
diff --git a/src_features/setPlugin/cmd_setPlugin.h b/src_features/setPlugin/cmd_setPlugin.h
new file mode 100644
index 000000000..5749a1dbf
--- /dev/null
+++ b/src_features/setPlugin/cmd_setPlugin.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void set_swap_with_calldata_plugin_type(void);
diff --git a/src_features/signMessage/cmd_signMessage.c b/src_features/signMessage/cmd_signMessage.c
index 711073059..a2145ee99 100644
--- a/src_features/signMessage/cmd_signMessage.c
+++ b/src_features/signMessage/cmd_signMessage.c
@@ -15,18 +15,21 @@ static const char SIGN_MAGIC[] =
     "\x19"
     "Ethereum Signed Message:\n";
 
+#define SET_IDLE                 \
+    do {                         \
+        if (states.ui_started) { \
+            ui_idle();           \
+        }                        \
+    } while (0)
+
 /**
  * Send a response APDU with the given Status Word
  *
  * @param[in] sw status word
  */
 static void apdu_reply(uint16_t sw) {
-    if ((sw != APDU_RESPONSE_OK) && states.ui_started) {
-        ui_idle();
-    }
-    G_io_apdu_buffer[0] = (sw >> 8) & 0xff;
-    G_io_apdu_buffer[1] = sw & 0xff;
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
+    bool idle = (sw != APDU_RESPONSE_OK) && states.ui_started;
+    io_seproxyhal_send_status(sw, 0, false, idle);
 }
 
 /**
@@ -89,9 +92,10 @@ static void reset_ui_buffer(void) {
  *
  * @param[in] data the APDU payload
  * @param[in] length the payload size
- * @return pointer to the start of the start of the message; \ref NULL if it failed
+ * @param[out] sw Status Word
+ * @return pointer to the start of the message; \ref NULL if it failed
  */
-static const uint8_t *first_apdu_data(const uint8_t *data, uint8_t *length) {
+static const uint8_t *first_apdu_data(const uint8_t *data, uint8_t *length, uint16_t *sw) {
     cx_err_t error = CX_INTERNAL_ERROR;
 
     if (appState != APP_STATE_IDLE) {
@@ -100,13 +104,13 @@ static const uint8_t *first_apdu_data(const uint8_t *data, uint8_t *length) {
     appState = APP_STATE_SIGNING_MESSAGE;
     data = parseBip32(data, length, &tmpCtx.messageSigningContext.bip32);
     if (data == NULL) {
-        apdu_reply(APDU_RESPONSE_INVALID_DATA);
+        *sw = APDU_RESPONSE_INVALID_DATA;
         return NULL;
     }
 
     if (*length < sizeof(uint32_t)) {
         PRINTF("Invalid data\n");
-        apdu_reply(APDU_RESPONSE_INVALID_DATA);
+        *sw = APDU_RESPONSE_INVALID_DATA;
         return NULL;
     }
 
@@ -135,8 +139,10 @@ static const uint8_t *first_apdu_data(const uint8_t *data, uint8_t *length) {
     reset_ui_buffer();
     states.sign_state = STATE_191_HASH_DISPLAY;
     states.ui_started = false;
+    *sw = APDU_RESPONSE_OK;
     return data;
 end:
+    *sw = error;
     return NULL;
 }
 
@@ -147,15 +153,15 @@ static const uint8_t *first_apdu_data(const uint8_t *data, uint8_t *length) {
  * @param[in] length the data length
  * @return whether it was successful or not
  */
-static bool feed_hash(const uint8_t *const data, const uint8_t length) {
+static uint16_t feed_hash(const uint8_t *const data, const uint8_t length) {
     cx_err_t error = CX_INTERNAL_ERROR;
 
     if (length > tmpCtx.messageSigningContext.remainingLength) {
         PRINTF("Error: Length mismatch ! (%u > %u)!\n",
                length,
                tmpCtx.messageSigningContext.remainingLength);
-        apdu_reply(APDU_RESPONSE_INVALID_DATA);
-        return false;
+        SET_IDLE;
+        return APDU_RESPONSE_INVALID_DATA;
     }
     CX_CHECK(cx_hash_no_throw((cx_hash_t *) &global_sha3, 0, data, length, NULL, 0));
     if ((tmpCtx.messageSigningContext.remainingLength -= length) == 0) {
@@ -167,15 +173,15 @@ static bool feed_hash(const uint8_t *const data, const uint8_t length) {
                                   tmpCtx.messageSigningContext.hash,
                                   32));
     }
-    return true;
+    error = APDU_RESPONSE_OK;
 end:
-    return false;
+    return error;
 }
 
 /**
  * Feed the UI with new data
  */
-static void feed_display(void) {
+static uint16_t feed_display(void) {
     int c;
 
     while ((unprocessed_length() > 0) && (remaining_ui_buffer_length() > 0)) {
@@ -210,57 +216,70 @@ static void feed_display(void) {
     }
 
     if ((unprocessed_length() == 0) && (tmpCtx.messageSigningContext.remainingLength > 0)) {
-        apdu_reply(APDU_RESPONSE_OK);
+        return APDU_RESPONSE_OK;
     }
+    return APDU_NO_RESPONSE;
 }
 
 /**
  * EIP-191 APDU handler
  *
  * @param[in] p1 instruction parameter 1
- * @param[in] p2 instruction parameter 2
  * @param[in] payload received data
  * @param[in] length data length
+ * @param[in] flags io_exchange flag
  * @return whether the handling of the APDU was successful or not
  */
-bool handleSignPersonalMessage(uint8_t p1,
-                               uint8_t p2,
-                               const uint8_t *const payload,
-                               uint8_t length) {
+uint16_t handleSignPersonalMessage(uint8_t p1,
+                                   const uint8_t *const payload,
+                                   uint8_t length,
+                                   unsigned int *flags) {
     const uint8_t *data = payload;
+    uint16_t sw = APDU_RESPONSE_UNKNOWN;
 
-    (void) p2;
     processed_size = 0;
     if (p1 == P1_FIRST) {
-        if ((data = first_apdu_data(data, &length)) == NULL) {
-            return false;
+        if ((data = first_apdu_data(data, &length, &sw)) == NULL) {
+            if (sw != APDU_RESPONSE_INVALID_DATA) {
+                *flags |= IO_ASYNCH_REPLY;
+            }
+            return sw;
         }
         processed_size = data - payload;
     } else if (p1 != P1_MORE) {
         PRINTF("Error: Unexpected P1 (%u)!\n", p1);
-        apdu_reply(APDU_RESPONSE_INVALID_P1_P2);
-        return false;
+        SET_IDLE;
+        return APDU_RESPONSE_INVALID_P1_P2;
     } else if (appState != APP_STATE_SIGNING_MESSAGE) {
         PRINTF("Error: App not already in signing state!\n");
-        apdu_reply(APDU_RESPONSE_INVALID_DATA);
-        return false;
+        SET_IDLE;
+        return APDU_RESPONSE_INVALID_DATA;
     }
 
-    if (!feed_hash(data, length)) {
-        return false;
+    sw = feed_hash(data, length);
+    if (sw != APDU_RESPONSE_OK) {
+        if (sw != APDU_RESPONSE_INVALID_DATA) {
+            *flags |= IO_ASYNCH_REPLY;
+        }
+        return sw;
     }
 
     if (states.sign_state == STATE_191_HASH_DISPLAY) {
-        feed_display();
-    } else  // hash only
-    {
+        sw = feed_display();
+        if (sw != APDU_RESPONSE_OK) {
+            *flags |= IO_ASYNCH_REPLY;
+        }
+    } else {
+        // hash only
         if (tmpCtx.messageSigningContext.remainingLength == 0) {
             ui_191_switch_to_sign();
+            sw = APDU_NO_RESPONSE;
+            *flags |= IO_ASYNCH_REPLY;
         } else {
-            apdu_reply(APDU_RESPONSE_OK);
+            sw = APDU_RESPONSE_OK;
         }
     }
-    return true;
+    return sw;
 }
 
 /**
diff --git a/src_features/signMessage/ui_common_signMessage.c b/src_features/signMessage/ui_common_signMessage.c
index d58fd6cff..047b21a37 100644
--- a/src_features/signMessage/ui_common_signMessage.c
+++ b/src_features/signMessage/ui_common_signMessage.c
@@ -4,20 +4,17 @@
 #include "common_ui.h"
 
 unsigned int io_seproxyhal_touch_signMessage_ok(void) {
-    uint32_t tx = 0;
     unsigned int info = 0;
-    if (bip32_derive_ecdsa_sign_rs_hash_256(CX_CURVE_256K1,
-                                            tmpCtx.messageSigningContext.bip32.path,
-                                            tmpCtx.messageSigningContext.bip32.length,
-                                            CX_RND_RFC6979 | CX_LAST,
-                                            CX_SHA256,
-                                            tmpCtx.messageSigningContext.hash,
-                                            sizeof(tmpCtx.messageSigningContext.hash),
-                                            G_io_apdu_buffer + 1,
-                                            G_io_apdu_buffer + 1 + 32,
-                                            &info) != CX_OK) {
-        THROW(APDU_RESPONSE_UNKNOWN);
-    }
+    CX_ASSERT(bip32_derive_ecdsa_sign_rs_hash_256(CX_CURVE_256K1,
+                                                  tmpCtx.messageSigningContext.bip32.path,
+                                                  tmpCtx.messageSigningContext.bip32.length,
+                                                  CX_RND_RFC6979 | CX_LAST,
+                                                  CX_SHA256,
+                                                  tmpCtx.messageSigningContext.hash,
+                                                  sizeof(tmpCtx.messageSigningContext.hash),
+                                                  G_io_apdu_buffer + 1,
+                                                  G_io_apdu_buffer + 1 + 32,
+                                                  &info));
     G_io_apdu_buffer[0] = 27;
     if (info & CX_ECCINFO_PARITY_ODD) {
         G_io_apdu_buffer[0]++;
@@ -25,24 +22,9 @@ unsigned int io_seproxyhal_touch_signMessage_ok(void) {
     if (info & CX_ECCINFO_xGTn) {
         G_io_apdu_buffer[0] += 2;
     }
-    tx = 65;
-    G_io_apdu_buffer[tx++] = 0x90;
-    G_io_apdu_buffer[tx++] = 0x00;
-    reset_app_context();
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+    return io_seproxyhal_send_status(APDU_RESPONSE_OK, 65, true, false);
 }
 
 unsigned int io_seproxyhal_touch_signMessage_cancel(void) {
-    reset_app_context();
-    G_io_apdu_buffer[0] = 0x69;
-    G_io_apdu_buffer[1] = 0x85;
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+    return io_seproxyhal_send_status(APDU_RESPONSE_CONDITION_NOT_SATISFIED, 0, true, false);
 }
diff --git a/src_features/signMessageEIP712/commands_712.c b/src_features/signMessageEIP712/commands_712.c
index 179cff749..dd3485a7e 100644
--- a/src_features/signMessageEIP712/commands_712.c
+++ b/src_features/signMessageEIP712/commands_712.c
@@ -27,7 +27,9 @@
 #define P2_IMPL_ARRAY             0x0F
 #define P2_IMPL_FIELD             P2_DEF_FIELD
 #define P2_FILT_ACTIVATE          0x00
+#define P2_FILT_DISCARDED_PATH    0x01
 #define P2_FILT_MESSAGE_INFO      0x0F
+#define P2_FILT_CONTRACT_NAME     0xFB
 #define P2_FILT_DATE_TIME         0xFC
 #define P2_FILT_AMOUNT_JOIN_TOKEN 0xFD
 #define P2_FILT_AMOUNT_JOIN_VALUE 0xFE
@@ -41,130 +43,157 @@
  *
  * @param[in] success whether the command was successful
  */
-void handle_eip712_return_code(bool success) {
+static void apdu_reply(bool success) {
+    bool home = true;
+
     if (success) {
         apdu_response_code = APDU_RESPONSE_OK;
-    } else if (apdu_response_code == APDU_RESPONSE_OK) {  // somehow not set
-        apdu_response_code = APDU_RESPONSE_ERROR_NO_INFO;
+    } else {
+        if (apdu_response_code == APDU_RESPONSE_OK) {  // somehow not set
+            apdu_response_code = APDU_RESPONSE_ERROR_NO_INFO;
+        }
+        if (eip712_context != NULL) {
+            home = eip712_context->go_home_on_failure;
+        }
+        eip712_context_deinit();
+        if (home) ui_idle();
     }
+}
 
-    G_io_apdu_buffer[0] = (apdu_response_code >> 8) & 0xff;
-    G_io_apdu_buffer[1] = apdu_response_code & 0xff;
-
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
+/**
+ * Send the response to the previous APDU command
+ *
+ * In case of an error it uses the global variable to retrieve the error code and resets
+ * the app context
+ *
+ * @param[in] success whether the command was successful
+ */
+void handle_eip712_return_code(bool success) {
+    apdu_reply(success);
 
-    if (!success) {
-        eip712_context_deinit();
-        ui_idle();
-    }
+    io_seproxyhal_send_status(apdu_response_code, 0, false, false);
 }
 
 /**
  * Process the EIP712 struct definition command
  *
- * @param[in] apdu_buf the APDU payload
+ * @param[in] p2 instruction parameter 2
+ * @param[in] cdata command data
+ * @param[in] length length of the command data
  * @return whether the command was successful or not
  */
-bool handle_eip712_struct_def(const uint8_t *const apdu_buf) {
+uint16_t handle_eip712_struct_def(uint8_t p2, const uint8_t *cdata, uint8_t length) {
     bool ret = true;
 
     if (eip712_context == NULL) {
         ret = eip712_context_init();
     }
-
     if (struct_state == DEFINED) {
         ret = false;
     }
 
     if (ret) {
-        switch (apdu_buf[OFFSET_P2]) {
+        switch (p2) {
             case P2_DEF_NAME:
-                ret = set_struct_name(apdu_buf[OFFSET_LC], &apdu_buf[OFFSET_CDATA]);
+                ret = set_struct_name(length, cdata);
                 break;
             case P2_DEF_FIELD:
-                ret = set_struct_field(apdu_buf[OFFSET_LC], &apdu_buf[OFFSET_CDATA]);
+                ret = set_struct_field(length, cdata);
                 break;
             default:
-                PRINTF("Unknown P2 0x%x for APDU 0x%x\n",
-                       apdu_buf[OFFSET_P2],
-                       apdu_buf[OFFSET_INS]);
+                PRINTF("Unknown P2 0x%x\n", p2);
                 apdu_response_code = APDU_RESPONSE_INVALID_P1_P2;
                 ret = false;
         }
     }
-    handle_eip712_return_code(ret);
-    return ret;
+    apdu_reply(ret);
+    return apdu_response_code;
 }
 
 /**
  * Process the EIP712 struct implementation command
  *
- * @param[in] apdu_buf the APDU payload
+ * @param[in] p1 instruction parameter 1
+ * @param[in] p2 instruction parameter 2
+ * @param[in] cdata command data
+ * @param[in] length length of the command data
  * @return whether the command was successful or not
  */
-bool handle_eip712_struct_impl(const uint8_t *const apdu_buf) {
+uint16_t handle_eip712_struct_impl(uint8_t p1,
+                                   uint8_t p2,
+                                   const uint8_t *cdata,
+                                   uint8_t length,
+                                   uint32_t *flags) {
     bool ret = false;
     bool reply_apdu = true;
 
     if (eip712_context == NULL) {
         apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED;
     } else {
-        switch (apdu_buf[OFFSET_P2]) {
+        switch (p2) {
             case P2_IMPL_NAME:
                 // set root type
-                ret = path_set_root((char *) &apdu_buf[OFFSET_CDATA], apdu_buf[OFFSET_LC]);
+                ret = path_set_root((char *) cdata, length);
                 if (ret) {
+#ifdef SCREEN_SIZE_WALLET
+                    if (ui_712_get_filtering_mode() == EIP712_FILTERING_BASIC) {
+#else
                     if (N_storage.verbose_eip712) {
-                        ui_712_review_struct(path_get_root());
-                        reply_apdu = false;
+#endif
+                        if ((ret = ui_712_review_struct(path_get_root()))) {
+                            reply_apdu = false;
+                        }
                     }
                     ui_712_field_flags_reset();
                 }
                 break;
             case P2_IMPL_FIELD:
-                if ((ret = field_hash(&apdu_buf[OFFSET_CDATA],
-                                      apdu_buf[OFFSET_LC],
-                                      apdu_buf[OFFSET_P1] != P1_COMPLETE))) {
+                if ((ret = field_hash(cdata, length, p1 != P1_COMPLETE))) {
                     reply_apdu = false;
                 }
                 break;
             case P2_IMPL_ARRAY:
-                ret = path_new_array_depth(&apdu_buf[OFFSET_CDATA], apdu_buf[OFFSET_LC]);
+                ret = path_new_array_depth(cdata, length);
                 break;
             default:
-                PRINTF("Unknown P2 0x%x for APDU 0x%x\n",
-                       apdu_buf[OFFSET_P2],
-                       apdu_buf[OFFSET_INS]);
+                PRINTF("Unknown P2 0x%x\n", p2);
                 apdu_response_code = APDU_RESPONSE_INVALID_P1_P2;
         }
     }
     if (reply_apdu) {
-        handle_eip712_return_code(ret);
+        apdu_reply(ret);
+        return apdu_response_code;
     }
-    return ret;
+    *flags |= IO_ASYNCH_REPLY;
+    return APDU_NO_RESPONSE;
 }
 
 /**
  * Process the EIP712 filtering command
  *
- * @param[in] apdu_buf the APDU payload
+ * @param[in] p1 instruction parameter 1
+ * @param[in] p2 instruction parameter 2
+ * @param[in] cdata command data
+ * @param[in] length length of the command data
  * @return whether the command was successful or not
  */
-bool handle_eip712_filtering(const uint8_t *const apdu_buf) {
+uint16_t handle_eip712_filtering(uint8_t p1,
+                                 uint8_t p2,
+                                 const uint8_t *cdata,
+                                 uint8_t length,
+                                 uint32_t *flags) {
     bool ret = true;
     bool reply_apdu = true;
+    uint32_t path_crc = 0;
 
     if (eip712_context == NULL) {
-        apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED;
-        return false;
+        apdu_reply(false);
+        return APDU_RESPONSE_CONDITION_NOT_SATISFIED;
     }
-    if ((apdu_buf[OFFSET_P2] != P2_FILT_ACTIVATE) &&
-        (ui_712_get_filtering_mode() != EIP712_FILTERING_FULL)) {
-        handle_eip712_return_code(true);
-        return true;
+    if ((p2 != P2_FILT_ACTIVATE) && (ui_712_get_filtering_mode() != EIP712_FILTERING_FULL)) {
+        return APDU_RESPONSE_OK;
     }
-    switch (apdu_buf[OFFSET_P2]) {
+    switch (p2) {
         case P2_FILT_ACTIVATE:
             if (!N_storage.verbose_eip712) {
                 ui_712_set_filtering_mode(EIP712_FILTERING_FULL);
@@ -172,31 +201,39 @@ bool handle_eip712_filtering(const uint8_t *const apdu_buf) {
             }
             forget_known_assets();
             break;
+        case P2_FILT_DISCARDED_PATH:
+            ret = filtering_discarded_path(cdata, length);
+            break;
         case P2_FILT_MESSAGE_INFO:
-            ret = filtering_message_info(&apdu_buf[OFFSET_CDATA], apdu_buf[OFFSET_LC]);
+            ret = filtering_message_info(cdata, length);
             if (ret) {
                 reply_apdu = false;
             }
             break;
+#ifdef HAVE_TRUSTED_NAME
+        case P2_FILT_CONTRACT_NAME:
+            ret = filtering_trusted_name(cdata, length, p1 == 1, &path_crc);
+            break;
+#endif
         case P2_FILT_DATE_TIME:
-            ret = filtering_date_time(&apdu_buf[OFFSET_CDATA], apdu_buf[OFFSET_LC]);
+            ret = filtering_date_time(cdata, length, p1 == 1, &path_crc);
             break;
         case P2_FILT_AMOUNT_JOIN_TOKEN:
-            ret = filtering_amount_join_token(&apdu_buf[OFFSET_CDATA], apdu_buf[OFFSET_LC]);
+            ret = filtering_amount_join_token(cdata, length, p1 == 1, &path_crc);
             break;
         case P2_FILT_AMOUNT_JOIN_VALUE:
-            ret = filtering_amount_join_value(&apdu_buf[OFFSET_CDATA], apdu_buf[OFFSET_LC]);
+            ret = filtering_amount_join_value(cdata, length, p1 == 1, &path_crc);
             break;
         case P2_FILT_RAW_FIELD:
-            ret = filtering_raw_field(&apdu_buf[OFFSET_CDATA], apdu_buf[OFFSET_LC]);
+            ret = filtering_raw_field(cdata, length, p1 == 1, &path_crc);
             break;
         default:
-            PRINTF("Unknown P2 0x%x for APDU 0x%x\n", apdu_buf[OFFSET_P2], apdu_buf[OFFSET_INS]);
+            PRINTF("Unknown P2 0x%x\n", p2);
             apdu_response_code = APDU_RESPONSE_INVALID_P1_P2;
             ret = false;
     }
-    if ((apdu_buf[OFFSET_P2] > P2_FILT_MESSAGE_INFO) && ret) {
-        if (ui_712_push_new_filter_path()) {
+    if ((p2 > P2_FILT_MESSAGE_INFO) && ret) {
+        if (ui_712_push_new_filter_path(path_crc)) {
             if (!ui_712_filters_counter_incr()) {
                 ret = false;
                 apdu_response_code = APDU_RESPONSE_INVALID_DATA;
@@ -204,9 +241,11 @@ bool handle_eip712_filtering(const uint8_t *const apdu_buf) {
         }
     }
     if (reply_apdu) {
-        handle_eip712_return_code(ret);
+        apdu_reply(ret);
+        return apdu_response_code;
     }
-    return ret;
+    *flags |= IO_ASYNCH_REPLY;
+    return APDU_NO_RESPONSE;
 }
 
 /**
@@ -215,9 +254,8 @@ bool handle_eip712_filtering(const uint8_t *const apdu_buf) {
  * @param[in] apdu_buf the APDU payload
  * @return whether the command was successful or not
  */
-bool handle_eip712_sign(const uint8_t *const apdu_buf) {
+uint16_t handle_eip712_sign(const uint8_t *cdata, uint8_t length, uint32_t *flags) {
     bool ret = false;
-    uint8_t length = apdu_buf[OFFSET_LC];
 
     if (eip712_context == NULL) {
         apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED;
@@ -233,18 +271,24 @@ bool handle_eip712_sign(const uint8_t *const apdu_buf) {
                (ui_712_remaining_filters() != 0)) {
         PRINTF("%d EIP712 filters are missing\n", ui_712_remaining_filters());
         apdu_response_code = APDU_RESPONSE_REF_DATA_NOT_FOUND;
-    } else if (parseBip32(&apdu_buf[OFFSET_CDATA], &length, &tmpCtx.messageSigningContext.bip32) !=
-               NULL) {
+    } else if (parseBip32(cdata, &length, &tmpCtx.messageSigningContext.bip32) == NULL) {
+        apdu_response_code = APDU_RESPONSE_INVALID_DATA;
+    } else {
+#ifndef SCREEN_SIZE_WALLET
         if (!N_storage.verbose_eip712 && (ui_712_get_filtering_mode() == EIP712_FILTERING_BASIC)) {
             ui_712_message_hash();
         }
+#endif
         ret = true;
         ui_712_end_sign();
     }
+
     if (!ret) {
-        handle_eip712_return_code(ret);
+        apdu_reply(false);
+        return apdu_response_code;
     }
-    return ret;
+    *flags |= IO_ASYNCH_REPLY;
+    return APDU_NO_RESPONSE;
 }
 
 #endif  // HAVE_EIP712_FULL_SUPPORT
diff --git a/src_features/signMessageEIP712/commands_712.h b/src_features/signMessageEIP712/commands_712.h
index dcfcf4570..3bc3377f7 100644
--- a/src_features/signMessageEIP712/commands_712.h
+++ b/src_features/signMessageEIP712/commands_712.h
@@ -8,10 +8,18 @@
 
 #define DOMAIN_STRUCT_NAME "EIP712Domain"
 
-bool handle_eip712_struct_def(const uint8_t *const apdu_buf);
-bool handle_eip712_struct_impl(const uint8_t *const apdu_buf);
-bool handle_eip712_sign(const uint8_t *const apdu_buf);
-bool handle_eip712_filtering(const uint8_t *const apdu_buf);
+uint16_t handle_eip712_struct_def(uint8_t p2, const uint8_t *cdata, uint8_t length);
+uint16_t handle_eip712_struct_impl(uint8_t p1,
+                                   uint8_t p2,
+                                   const uint8_t *cdata,
+                                   uint8_t length,
+                                   uint32_t *flags);
+uint16_t handle_eip712_sign(const uint8_t *cdata, uint8_t length, uint32_t *flags);
+uint16_t handle_eip712_filtering(uint8_t p1,
+                                 uint8_t p2,
+                                 const uint8_t *cdata,
+                                 uint8_t length,
+                                 uint32_t *flags);
 void handle_eip712_return_code(bool success);
 
 #endif  // HAVE_EIP712_FULL_SUPPORT
diff --git a/src_features/signMessageEIP712/context_712.c b/src_features/signMessageEIP712/context_712.c
index 57d5be6dd..89a2a98b0 100644
--- a/src_features/signMessageEIP712/context_712.c
+++ b/src_features/signMessageEIP712/context_712.c
@@ -55,6 +55,7 @@ bool eip712_context_init(void) {
     // Since they are optional, they might not be provided by the JSON data
     explicit_bzero(eip712_context->contract_addr, sizeof(eip712_context->contract_addr));
     eip712_context->chain_id = 0;
+    eip712_context->go_home_on_failure = true;
 
     struct_state = NOT_INITIALIZED;
 
diff --git a/src_features/signMessageEIP712/context_712.h b/src_features/signMessageEIP712/context_712.h
index 2ae5c8daf..2b020973f 100644
--- a/src_features/signMessageEIP712/context_712.h
+++ b/src_features/signMessageEIP712/context_712.h
@@ -10,6 +10,7 @@ typedef struct {
     uint8_t contract_addr[ADDRESS_LENGTH];
     uint64_t chain_id;
     uint8_t schema_hash[224 / 8];
+    bool go_home_on_failure;
 } s_eip712_context;
 
 extern s_eip712_context *eip712_context;
diff --git a/src_features/signMessageEIP712/filtering.c b/src_features/signMessageEIP712/filtering.c
index efefd6466..bb43b36a4 100644
--- a/src_features/signMessageEIP712/filtering.c
+++ b/src_features/signMessageEIP712/filtering.c
@@ -12,46 +12,64 @@
 #include "path.h"
 #include "ui_logic.h"
 #include "filtering.h"
+#ifdef HAVE_LEDGER_PKI
+#include "os_pki.h"
+#endif
+#include "trusted_name.h"
 
 #define FILT_MAGIC_MESSAGE_INFO      183
 #define FILT_MAGIC_AMOUNT_JOIN_TOKEN 11
 #define FILT_MAGIC_AMOUNT_JOIN_VALUE 22
 #define FILT_MAGIC_DATETIME          33
+#define FILT_MAGIC_TRUSTED_NAME      44
 #define FILT_MAGIC_RAW_FIELD         72
 
 #define TOKEN_IDX_ADDR_IN_DOMAIN 0xff
 
 /**
- * Reconstruct the field path and hash it
+ * Reconstruct the field path and hash it for the signature and the CRC
  *
  * @param[in] hash_ctx the hashing context
+ * @param[in] discarded if the filter targets a field that does not exist (within an empty array)
+ * @param[out] path_crc pointer to the CRC of the filter path
  */
-static void hash_filtering_path(cx_hash_t *hash_ctx) {
+static void hash_filtering_path(cx_hash_t *hash_ctx, bool discarded, uint32_t *path_crc) {
     const void *field_ptr;
     const char *key;
     uint8_t key_len;
 
-    for (uint8_t i = 0; i < path_get_depth_count(); ++i) {
-        if (i > 0) {
-            hash_byte('.', hash_ctx);
-        }
-        if ((field_ptr = path_get_nth_field(i + 1)) != NULL) {
-            if ((key = get_struct_field_keyname(field_ptr, &key_len)) != NULL) {
-                // field name
-                hash_nbytes((uint8_t *) key, key_len, hash_ctx);
-
-                // array levels
-                if (struct_field_is_array(field_ptr)) {
-                    uint8_t lvl_count;
-
-                    get_struct_field_array_lvls_array(field_ptr, &lvl_count);
-                    for (int j = 0; j < lvl_count; ++j) {
-                        hash_nbytes((uint8_t *) ".[]", 3, hash_ctx);
+    if (discarded) {
+        key = ui_712_get_discarded_path(&key_len);
+        hash_nbytes((uint8_t *) key, key_len, hash_ctx);
+        *path_crc = cx_crc32_update(*path_crc, key, key_len);
+    } else {
+        for (uint8_t i = 0; i < path_get_depth_count(); ++i) {
+            if (i > 0) {
+                hash_byte('.', hash_ctx);
+                *path_crc = cx_crc32_update(*path_crc, ".", 1);
+            }
+            if ((field_ptr = path_get_nth_field(i + 1)) != NULL) {
+                if ((key = get_struct_field_keyname(field_ptr, &key_len)) != NULL) {
+                    // field name
+                    hash_nbytes((uint8_t *) key, key_len, hash_ctx);
+                    *path_crc = cx_crc32_update(*path_crc, key, key_len);
+
+                    // array levels
+                    if (struct_field_is_array(field_ptr)) {
+                        uint8_t lvl_count;
+
+                        get_struct_field_array_lvls_array(field_ptr, &lvl_count);
+                        for (int j = 0; j < lvl_count; ++j) {
+                            hash_nbytes((uint8_t *) ".[]", 3, hash_ctx);
+                            *path_crc = cx_crc32_update(*path_crc, ".[]", 3);
+                        }
                     }
                 }
             }
         }
     }
+    // so it is only usable for the following filter
+    ui_712_set_discarded_path("", 0);
 }
 
 /**
@@ -95,26 +113,26 @@ static bool sig_verif_start(cx_sha256_t *hash_ctx, uint8_t magic) {
  */
 static bool sig_verif_end(cx_sha256_t *hash_ctx, const uint8_t *sig, uint8_t sig_length) {
     uint8_t hash[INT256_LENGTH];
-    cx_ecfp_public_key_t verifying_key;
     cx_err_t error = CX_INTERNAL_ERROR;
+    bool ret_code = false;
 
     // Finalize hash
     CX_CHECK(cx_hash_no_throw((cx_hash_t *) hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH));
 
-    CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1,
-                                              LEDGER_SIGNATURE_PUBLIC_KEY,
-                                              sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
-                                              &verifying_key));
-    if (!cx_ecdsa_verify_no_throw(&verifying_key, hash, sizeof(hash), sig, sig_length)) {
-#ifndef HAVE_BYPASS_SIGNATURES
-        PRINTF("Invalid EIP-712 filtering signature\n");
-        apdu_response_code = APDU_RESPONSE_INVALID_DATA;
-        return false;
+    CX_CHECK(check_signature_with_pubkey("EIP712 Filtering",
+                                         hash,
+                                         sizeof(hash),
+                                         LEDGER_SIGNATURE_PUBLIC_KEY,
+                                         sizeof(LEDGER_SIGNATURE_PUBLIC_KEY),
+#ifdef HAVE_LEDGER_PKI
+                                         CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META,
 #endif
-    }
-    return true;
+                                         (uint8_t *) (sig),
+                                         sig_length));
+
+    ret_code = true;
 end:
-    return false;
+    return ret_code;
 }
 
 /**
@@ -128,10 +146,6 @@ static bool check_token_index(uint8_t idx) {
         PRINTF("Error: token index out of range (%u)\n", idx);
         return false;
     }
-    if (!tmpCtx.transactionContext.assetSet[idx]) {
-        PRINTF("Error: token not set (%u)\n", idx);
-        return false;
-    }
     return true;
 }
 
@@ -223,14 +237,225 @@ bool filtering_message_info(const uint8_t *payload, uint8_t length) {
     return true;
 }
 
+/**
+ * Check if given path matches the backed-up path
+ *
+ * A match is found as long as the given path starts with the backed-up path.
+ *
+ * @param[in] path given path
+ * @param[in] path_len length of the path
+ * @param[out] offset_ptr offset to where the comparison stopped
+ * @return whether a match was found or not
+ */
+static bool matches_backup_path(const char *path, uint8_t path_len, uint8_t *offset_ptr) {
+    const void *field_ptr;
+    const char *key;
+    uint8_t key_len;
+    uint8_t offset = 0;
+    uint8_t lvl_count;
+
+    for (uint8_t i = 0; i < path_backup_get_depth_count(); ++i) {
+        if (i > 0) {
+            if (((offset + 1) > path_len) || (memcmp(path + offset, ".", 1) != 0)) {
+                return false;
+            }
+            offset += 1;
+        }
+        if ((field_ptr = path_backup_get_nth_field(i + 1)) != NULL) {
+            if ((key = get_struct_field_keyname(field_ptr, &key_len)) != NULL) {
+                // field name
+                if (((offset + key_len) > path_len) || (memcmp(path + offset, key, key_len) != 0)) {
+                    return false;
+                }
+                offset += key_len;
+
+                // array levels
+                if (struct_field_is_array(field_ptr)) {
+                    get_struct_field_array_lvls_array(field_ptr, &lvl_count);
+                    for (int j = 0; j < lvl_count; ++j) {
+                        if (((offset + 3) > path_len) || (memcmp(path + offset, ".[]", 3) != 0)) {
+                            return false;
+                        }
+                        offset += 3;
+                    }
+                }
+            }
+        }
+    }
+    if (offset_ptr != NULL) {
+        *offset_ptr = offset;
+    }
+    return true;
+}
+
+/**
+ * Command to provide the filter path of a discarded filtered field
+ *
+ * Some filtered fields are discarded/never received because they are contained in an array
+ * that turns out to be empty.
+ *
+ * @param[in] payload the payload to parse
+ * @param[in] length the payload length
+ * @return whether it was successful or not
+ */
+bool filtering_discarded_path(const uint8_t *payload, uint8_t length) {
+    uint8_t path_len;
+    const char *path;
+    uint8_t offset = 0;
+    uint8_t path_offset;
+
+    if ((offset + sizeof(path_len)) > length) {
+        return false;
+    }
+    path_len = payload[offset++];
+    if ((offset + path_len) > length) {
+        return false;
+    }
+    path = (char *) &payload[offset];
+    offset += path_len;
+    if (offset < path_len) {
+        return false;
+    }
+    if (!matches_backup_path(path, path_len, &path_offset)) {
+        return false;
+    }
+    if (!path_exists_in_backup(path + path_offset, path_len - path_offset)) {
+        return false;
+    }
+    ui_712_set_discarded_path(path, path_len);
+    return true;
+}
+
+#ifdef HAVE_TRUSTED_NAME
+/**
+ * Command to display a field as a trusted name
+ *
+ * @param[in] payload the payload to parse
+ * @param[in] length the payload length
+ * @param[in] discarded if the filter targets a field that is does not exist (within an empty array)
+ * @param[out] path_crc pointer to the CRC of the filter path
+ * @return whether it was successful or not
+ */
+bool filtering_trusted_name(const uint8_t *payload,
+                            uint8_t length,
+                            bool discarded,
+                            uint32_t *path_crc) {
+    uint8_t name_len;
+    const char *name;
+    uint8_t types_count;
+    e_name_type *types;
+    uint8_t sources_count;
+    e_name_source *sources;
+    uint8_t sig_len;
+    const uint8_t *sig;
+    uint8_t offset = 0;
+
+    if (path_get_root_type() != ROOT_MESSAGE) {
+        apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED;
+        return false;
+    }
+
+    // Parsing
+    if ((offset + sizeof(name_len)) > length) {
+        return false;
+    }
+    name_len = payload[offset++];
+    if ((offset + name_len) > length) {
+        return false;
+    }
+    name = (char *) &payload[offset];
+    offset += name_len;
+    if ((offset + sizeof(types_count)) > length) {
+        return false;
+    }
+    types_count = payload[offset++];
+    if ((offset + types_count) > length) {
+        return false;
+    }
+    types = (e_name_type *) &payload[offset];
+    // sanity check
+    for (int i = 0; i < types_count; ++i) {
+        switch (types[i]) {
+            case TYPE_ACCOUNT:
+            case TYPE_CONTRACT:
+                break;
+            default:
+                return false;
+        }
+    }
+    offset += types_count;
+    if ((offset + sizeof(sources_count)) > length) {
+        return false;
+    }
+    sources_count = payload[offset++];
+    if ((offset + sources_count) > length) {
+        return false;
+    }
+    sources = (e_name_source *) &payload[offset];
+    // sanity check
+    for (int i = 0; i < sources_count; ++i) {
+        switch (sources[i]) {
+            case SOURCE_LAB:
+            case SOURCE_CAL:
+            case SOURCE_ENS:
+            case SOURCE_UD:
+            case SOURCE_FN:
+            case SOURCE_DNS:
+                break;
+            default:
+                return false;
+        }
+    }
+    offset += sources_count;
+    //
+    if ((offset + sizeof(sig_len)) > length) {
+        return false;
+    }
+    sig_len = payload[offset++];
+    if ((offset + sig_len) != length) {
+        return false;
+    }
+    sig = &payload[offset];
+
+    // Verification
+    cx_sha256_t hash_ctx;
+    if (!sig_verif_start(&hash_ctx, FILT_MAGIC_TRUSTED_NAME)) {
+        return false;
+    }
+    hash_filtering_path((cx_hash_t *) &hash_ctx, discarded, path_crc);
+    hash_nbytes((uint8_t *) name, sizeof(char) * name_len, (cx_hash_t *) &hash_ctx);
+    hash_nbytes(types, types_count, (cx_hash_t *) &hash_ctx);
+    hash_nbytes(sources, sources_count, (cx_hash_t *) &hash_ctx);
+    if (!sig_verif_end(&hash_ctx, sig, sig_len)) {
+        return false;
+    }
+
+    // Handling
+    if (!check_typename("address")) {
+        return false;
+    }
+    if (name_len > 0) {  // don't substitute for an empty name
+        ui_712_set_title(name, name_len);
+    }
+    ui_712_flag_field(true, name_len > 0, false, false, true);
+    ui_712_set_trusted_name_requirements(types_count, types);
+    return true;
+}
+#endif  // HAVE_TRUSTED_NAME
+
 /**
  * Command to display a field as a date-time
  *
  * @param[in] payload the payload to parse
  * @param[in] length the payload length
+ * @param[in] discarded if the filter targets a field that is does not exist (within an empty array)
+ * @param[out] path_crc pointer to the CRC of the filter path
  * @return whether it was successful or not
  */
-bool filtering_date_time(const uint8_t *payload, uint8_t length) {
+bool filtering_date_time(const uint8_t *payload,
+                         uint8_t length,
+                         bool discarded,
+                         uint32_t *path_crc) {
     uint8_t name_len;
     const char *name;
     uint8_t sig_len;
@@ -266,7 +491,7 @@ bool filtering_date_time(const uint8_t *payload, uint8_t length) {
     if (!sig_verif_start(&hash_ctx, FILT_MAGIC_DATETIME)) {
         return false;
     }
-    hash_filtering_path((cx_hash_t *) &hash_ctx);
+    hash_filtering_path((cx_hash_t *) &hash_ctx, discarded, path_crc);
     hash_nbytes((uint8_t *) name, sizeof(char) * name_len, (cx_hash_t *) &hash_ctx);
     if (!sig_verif_end(&hash_ctx, sig, sig_len)) {
         return false;
@@ -279,7 +504,7 @@ bool filtering_date_time(const uint8_t *payload, uint8_t length) {
     if (name_len > 0) {  // don't substitute for an empty name
         ui_712_set_title(name, name_len);
     }
-    ui_712_flag_field(true, name_len > 0, false, true);
+    ui_712_flag_field(true, name_len > 0, false, true, false);
     return true;
 }
 
@@ -288,9 +513,14 @@ bool filtering_date_time(const uint8_t *payload, uint8_t length) {
  *
  * @param[in] payload the payload to parse
  * @param[in] length the payload length
+ * @param[in] discarded if the filter targets a field that is does not exist (within an empty array)
+ * @param[out] path_crc pointer to the CRC of the filter path
  * @return whether it was successful or not
  */
-bool filtering_amount_join_token(const uint8_t *payload, uint8_t length) {
+bool filtering_amount_join_token(const uint8_t *payload,
+                                 uint8_t length,
+                                 bool discarded,
+                                 uint32_t *path_crc) {
     uint8_t token_idx;
     uint8_t sig_len;
     const uint8_t *sig;
@@ -320,7 +550,7 @@ bool filtering_amount_join_token(const uint8_t *payload, uint8_t length) {
     if (!sig_verif_start(&hash_ctx, FILT_MAGIC_AMOUNT_JOIN_TOKEN)) {
         return false;
     }
-    hash_filtering_path((cx_hash_t *) &hash_ctx);
+    hash_filtering_path((cx_hash_t *) &hash_ctx, discarded, path_crc);
     hash_byte(token_idx, (cx_hash_t *) &hash_ctx);
     if (!sig_verif_end(&hash_ctx, sig, sig_len)) {
         return false;
@@ -330,7 +560,7 @@ bool filtering_amount_join_token(const uint8_t *payload, uint8_t length) {
     if (!check_typename("address") || !check_token_index(token_idx)) {
         return false;
     }
-    ui_712_flag_field(false, false, true, false);
+    ui_712_flag_field(false, false, true, false, false);
     ui_712_token_join_prepare_addr_check(token_idx);
     return true;
 }
@@ -340,9 +570,14 @@ bool filtering_amount_join_token(const uint8_t *payload, uint8_t length) {
  *
  * @param[in] payload the payload to parse
  * @param[in] length the payload length
+ * @param[in] discarded if the filter targets a field that is does not exist (within an empty array)
+ * @param[out] path_crc pointer to the CRC of the filter path
  * @return whether it was successful or not
  */
-bool filtering_amount_join_value(const uint8_t *payload, uint8_t length) {
+bool filtering_amount_join_value(const uint8_t *payload,
+                                 uint8_t length,
+                                 bool discarded,
+                                 uint32_t *path_crc) {
     uint8_t name_len;
     const char *name;
     uint8_t token_idx;
@@ -386,7 +621,7 @@ bool filtering_amount_join_value(const uint8_t *payload, uint8_t length) {
     if (!sig_verif_start(&hash_ctx, FILT_MAGIC_AMOUNT_JOIN_VALUE)) {
         return false;
     }
-    hash_filtering_path((cx_hash_t *) &hash_ctx);
+    hash_filtering_path((cx_hash_t *) &hash_ctx, discarded, path_crc);
     hash_nbytes((uint8_t *) name, sizeof(char) * name_len, (cx_hash_t *) &hash_ctx);
     hash_byte(token_idx, (cx_hash_t *) &hash_ctx);
     if (!sig_verif_end(&hash_ctx, sig, sig_len)) {
@@ -410,7 +645,7 @@ bool filtering_amount_join_value(const uint8_t *payload, uint8_t length) {
     if (!check_typename("uint") || !check_token_index(token_idx)) {
         return false;
     }
-    ui_712_flag_field(false, false, true, false);
+    ui_712_flag_field(false, false, true, false, false);
     ui_712_token_join_prepare_amount(token_idx, name, name_len);
     return true;
 }
@@ -420,9 +655,14 @@ bool filtering_amount_join_value(const uint8_t *payload, uint8_t length) {
  *
  * @param[in] payload the payload to parse
  * @param[in] length the payload length
+ * @param[in] discarded if the filter targets a field that is does not exist (within an empty array)
+ * @param[out] path_crc pointer to the CRC of the filter path
  * @return whether it was successful or not
  */
-bool filtering_raw_field(const uint8_t *payload, uint8_t length) {
+bool filtering_raw_field(const uint8_t *payload,
+                         uint8_t length,
+                         bool discarded,
+                         uint32_t *path_crc) {
     uint8_t name_len;
     const char *name;
     uint8_t sig_len;
@@ -458,17 +698,19 @@ bool filtering_raw_field(const uint8_t *payload, uint8_t length) {
     if (!sig_verif_start(&hash_ctx, FILT_MAGIC_RAW_FIELD)) {
         return false;
     }
-    hash_filtering_path((cx_hash_t *) &hash_ctx);
+    hash_filtering_path((cx_hash_t *) &hash_ctx, discarded, path_crc);
     hash_nbytes((uint8_t *) name, sizeof(char) * name_len, (cx_hash_t *) &hash_ctx);
     if (!sig_verif_end(&hash_ctx, sig, sig_len)) {
         return false;
     }
 
-    // Handling
-    if (name_len > 0) {  // don't substitute for an empty name
-        ui_712_set_title(name, name_len);
+    if (!discarded) {
+        // Handling
+        if (name_len > 0) {  // don't substitute for an empty name
+            ui_712_set_title(name, name_len);
+        }
+        ui_712_flag_field(true, name_len > 0, false, false, false);
     }
-    ui_712_flag_field(true, name_len > 0, false, false);
     return true;
 }
 
diff --git a/src_features/signMessageEIP712/filtering.h b/src_features/signMessageEIP712/filtering.h
index d35963cd9..71e8a9807 100644
--- a/src_features/signMessageEIP712/filtering.h
+++ b/src_features/signMessageEIP712/filtering.h
@@ -9,10 +9,27 @@
 #define MAX_FILTERS 50
 
 bool filtering_message_info(const uint8_t *payload, uint8_t length);
-bool filtering_date_time(const uint8_t *payload, uint8_t length);
-bool filtering_amount_join_token(const uint8_t *payload, uint8_t length);
-bool filtering_amount_join_value(const uint8_t *payload, uint8_t length);
-bool filtering_raw_field(const uint8_t *payload, uint8_t length);
+bool filtering_trusted_name(const uint8_t *payload,
+                            uint8_t length,
+                            bool discarded,
+                            uint32_t *path_crc);
+bool filtering_date_time(const uint8_t *payload,
+                         uint8_t length,
+                         bool discarded,
+                         uint32_t *path_crc);
+bool filtering_amount_join_token(const uint8_t *payload,
+                                 uint8_t length,
+                                 bool discarded,
+                                 uint32_t *path_crc);
+bool filtering_amount_join_value(const uint8_t *payload,
+                                 uint8_t length,
+                                 bool discarded,
+                                 uint32_t *path_crc);
+bool filtering_raw_field(const uint8_t *payload,
+                         uint8_t length,
+                         bool discarded,
+                         uint32_t *path_crc);
+bool filtering_discarded_path(const uint8_t *payload, uint8_t length);
 
 #endif  // HAVE_EIP712_FULL_SUPPORT
 
diff --git a/src_features/signMessageEIP712/path.c b/src_features/signMessageEIP712/path.c
index 732cbcb46..c163a4bb4 100644
--- a/src_features/signMessageEIP712/path.c
+++ b/src_features/signMessageEIP712/path.c
@@ -13,28 +13,30 @@
 #include "typed_data.h"
 
 static s_path *path_struct = NULL;
+static s_path *path_backup = NULL;
 
 /**
- * Get the field pointer to by the first N depths of the path.
+ * Get the field pointer to by the first N depths of the given path
  *
+ * @param[in] path given path struct
  * @param[out] fields_count_ptr the number of fields in the last evaluated depth
  * @param[in] n the number of depths to evaluate
  * @return the field which the first Nth depths points to
  */
-static const void *get_nth_field(uint8_t *const fields_count_ptr, uint8_t n) {
+static const void *get_nth_field_from(const s_path *path, uint8_t *fields_count_ptr, uint8_t n) {
     const void *struct_ptr = NULL;
     const void *field_ptr = NULL;
     const char *typename;
     uint8_t length;
     uint8_t fields_count;
 
-    if (path_struct == NULL) {
+    if (path == NULL) {
         return NULL;
     }
 
-    struct_ptr = path_struct->root_struct;
+    struct_ptr = path->root_struct;
 
-    if (n > path_struct->depth_count)  // sanity check
+    if (n > path->depth_count)  // sanity check
     {
         return NULL;
     }
@@ -45,11 +47,11 @@ static const void *get_nth_field(uint8_t *const fields_count_ptr, uint8_t n) {
             *fields_count_ptr = fields_count;
         }
         // check if the index at this depth makes sense
-        if (path_struct->depths[depth] > fields_count) {
+        if (path->depths[depth] > fields_count) {
             return NULL;
         }
 
-        for (uint8_t index = 0; index < path_struct->depths[depth]; ++index) {
+        for (uint8_t index = 0; index < path->depths[depth]; ++index) {
             field_ptr = get_next_struct_field(field_ptr);
         }
         if (struct_field_type(field_ptr) == TYPE_CUSTOM) {
@@ -62,6 +64,10 @@ static const void *get_nth_field(uint8_t *const fields_count_ptr, uint8_t n) {
     return field_ptr;
 }
 
+static const void *get_nth_field(uint8_t *fields_count_ptr, uint8_t n) {
+    return get_nth_field_from(path_struct, fields_count_ptr, n);
+}
+
 /**
  * Get the element the path is pointing to.
  *
@@ -82,6 +88,10 @@ const void *path_get_nth_field(uint8_t n) {
     return get_nth_field(NULL, n);
 }
 
+const void *path_backup_get_nth_field(uint8_t n) {
+    return get_nth_field_from(path_backup, NULL, n);
+}
+
 /**
  * Get Nth to last struct field from path
  *
@@ -164,12 +174,16 @@ static bool finalize_hash_depth(uint8_t *hash) {
  *
  * @param[in] hash pointer to given hash
  */
-static void feed_last_hash_depth(const uint8_t *const hash) {
+static bool feed_last_hash_depth(const uint8_t *const hash) {
     const cx_sha3_t *hash_ctx;
 
     hash_ctx = get_last_hash_ctx();
     // continue progressive hash with the array hash
-    CX_ASSERT(cx_hash_no_throw((cx_hash_t *) hash_ctx, 0, hash, KECCAK256_HASH_BYTESIZE, NULL, 0));
+    if (cx_hash_no_throw((cx_hash_t *) hash_ctx, 0, hash, KECCAK256_HASH_BYTESIZE, NULL, 0) !=
+        CX_OK) {
+        return false;
+    }
+    return true;
 }
 
 /**
@@ -214,7 +228,9 @@ static bool path_depth_list_pop(void) {
     to_feed = finalize_hash_depth(hash);
     if (path_struct->depth_count > 0) {
         if (to_feed) {
-            feed_last_hash_depth(hash);
+            if (feed_last_hash_depth(hash) == false) {
+                return false;
+            }
         }
     } else {
         switch (path_struct->root_type) {
@@ -275,7 +291,9 @@ static bool array_depth_list_pop(void) {
     }
 
     finalize_hash_depth(hash);  // return value not checked on purpose
-    feed_last_hash_depth(hash);
+    if (feed_last_hash_depth(hash) == false) {
+        return false;
+    }
 
     path_struct->array_depth_count -= 1;
     return true;
@@ -287,9 +305,10 @@ static bool array_depth_list_pop(void) {
  *
  * @param[in] skip_if_array skip if path is already pointing at an array
  * @param[in] stop_at_array stop at the first downstream array
+ * @param[in] do_typehash if a typehash needs to be done when a new struct is encountered
  * @return whether the path update worked or not
  */
-static bool path_update(bool skip_if_array, bool stop_at_array) {
+static bool path_update(bool skip_if_array, bool stop_at_array, bool do_typehash) {
     uint8_t fields_count;
     const void *struct_ptr;
     const void *starting_field_ptr;
@@ -327,14 +346,14 @@ static bool path_update(bool skip_if_array, bool stop_at_array) {
             return false;
         }
 
-        // The only times they are both at false is if we are traversing an empty array,
-        // don't do a typehash in that case
-        if ((skip_if_array != false) || (stop_at_array != false)) {
+        if (do_typehash) {
             // get the struct typehash
             if (type_hash(typename, typename_len, hash) == false) {
                 return false;
             }
-            feed_last_hash_depth(hash);
+            if (feed_last_hash_depth(hash) == false) {
+                return false;
+            }
         }
 
         // TODO: Find a better way to show inner structs in verbose mode when it might be
@@ -361,7 +380,9 @@ bool path_set_root(const char *const struct_name, uint8_t name_length) {
         return false;
     }
 
-    path_struct->root_struct = get_structn(struct_name, name_length);
+    if ((path_struct->root_struct = get_structn(struct_name, name_length)) == NULL) {
+        return false;
+    }
 
     if (path_struct->root_struct == NULL) {
         PRINTF("Struct name not found (");
@@ -379,8 +400,9 @@ bool path_set_root(const char *const struct_name, uint8_t name_length) {
     if (type_hash(struct_name, name_length, hash) == false) {
         return false;
     }
-    feed_last_hash_depth(hash);
-    //
+    if (feed_last_hash_depth(hash) == false) {
+        return false;
+    }
 
     // init depth, at 0 : empty path
     path_struct->depth_count = 0;
@@ -399,7 +421,7 @@ bool path_set_root(const char *const struct_name, uint8_t name_length) {
     struct_state = DEFINED;
 
     // because the first field could be a struct type
-    path_update(true, true);
+    path_update(true, true, true);
     return true;
 }
 
@@ -440,6 +462,27 @@ static bool check_and_add_array_depth(const void *depth,
     return true;
 }
 
+/**
+ * Back-up the current path
+ *
+ * Used for the handling of discarded filtered fields
+ */
+static void backup_path(void) {
+    const void *field_ptr;
+
+    memcpy(path_backup, path_struct, sizeof(*path_backup));
+    // decrease while it does not point to an array type
+    while (path_backup->depth_count > 1) {
+        if ((field_ptr = path_backup_get_nth_field(path_backup->depth_count)) == NULL) {
+            return;
+        }
+        if (struct_field_is_array(field_ptr)) {
+            break;
+        }
+        path_backup->depth_count -= 1;
+    }
+}
+
 /**
  * Add a new array depth with a given size (number of elements).
  *
@@ -467,7 +510,10 @@ bool path_new_array_depth(const uint8_t *const data, uint8_t length) {
     }
 
     array_size = *data;
-    if (!path_update(false, array_size > 0)) {
+    if (array_size == 0) {
+        backup_path();
+    }
+    if (!path_update(false, array_size > 0, array_size > 0)) {
         return false;
     }
     array_depth_count_bak = path_struct->array_depth_count;
@@ -583,7 +629,7 @@ static bool path_advance_in_array(void) {
  *
  * @return whether the advancement was successful or not
  */
-bool path_advance(bool array_check) {
+bool path_advance(bool do_typehash) {
     bool end_reached;
 
     do {
@@ -593,7 +639,7 @@ bool path_advance(bool array_check) {
             end_reached = false;
         }
     } while (end_reached);
-    return path_update(array_check, array_check);
+    return path_update(true, true, do_typehash);
 }
 
 /**
@@ -621,44 +667,90 @@ const void *path_get_root(void) {
 }
 
 /**
- * Get the current amount of depth
+ * Get the current amount of depth in a given path struct
  *
+ * @param[in] given path struct
  * @return depth count
  */
-uint8_t path_get_depth_count(void) {
-    if (path_struct == NULL) {
+static uint8_t get_depth_count(const s_path *path) {
+    if (path == NULL) {
         return 0;
     }
-    return path_struct->depth_count;
+    return path->depth_count;
 }
 
 /**
- * Generate a unique checksum out of the current path
+ * Get the current amount of depth in the path
  *
- * Goes over the fields of the \ref path_struct with a few exceptions : we skip the root_type since
- * we already go over root_struct, and in array_depths we only go over path_index since it would
- * otherwise generate a different CRC for different fields which are targeted by the same filtering
- * path.
+ * @return depth count
+ */
+uint8_t path_get_depth_count(void) {
+    return get_depth_count(path_struct);
+}
+
+/**
+ * Get the current amount of depth in the backup path
  *
- * @return CRC-32 checksum
+ * @return depth count
  */
-uint32_t get_path_crc(void) {
-    uint32_t value = CX_CRC32_INIT;
-
-    value = cx_crc32_update(value, &path_struct->root_struct, sizeof(path_struct->root_struct));
-    value = cx_crc32_update(value, &path_struct->depth_count, sizeof(path_struct->depth_count));
-    value = cx_crc32_update(value,
-                            path_struct->depths,
-                            sizeof(path_struct->depths[0]) * path_struct->depth_count);
-    value = cx_crc32_update(value,
-                            &path_struct->array_depth_count,
-                            sizeof(path_struct->array_depth_count));
-    for (int i = 0; i < path_struct->array_depth_count; ++i) {
-        value = cx_crc32_update(value,
-                                &path_struct->array_depths[i].path_index,
-                                sizeof(path_struct->array_depths[i].path_index));
-    }
-    return value;
+uint8_t path_backup_get_depth_count(void) {
+    return get_depth_count(path_backup);
+}
+
+/**
+ * Check if the given relative path exists in the backup path
+ *
+ * @param[in] path given path
+ * @param[in] length length of the path
+ * @return whether it exists or not
+ */
+bool path_exists_in_backup(const char *path, size_t length) {
+    size_t offset = 0;
+    size_t i;
+    const void *field_ptr;
+    const char *typename;
+    uint8_t typename_len;
+    const void *struct_ptr;
+    uint8_t fields_count;
+    const char *key;
+    uint8_t key_len;
+
+    field_ptr = get_nth_field_from(path_backup, NULL, path_backup->depth_count);
+    while (offset < length) {
+        if (((offset + 1) > length) || (memcmp(path + offset, ".", 1) != 0)) {
+            return false;
+        }
+        offset += 1;
+        if (((offset + 2) <= length) && (memcmp(path + offset, "[]", 2) == 0)) {
+            if (!struct_field_is_array(field_ptr)) {
+                return false;
+            }
+            offset += 2;
+        } else if (offset < length) {
+            for (i = 0; ((offset + i) < length) && (path[offset + i] != '.'); ++i)
+                ;
+            typename = get_struct_field_custom_typename(field_ptr, &typename_len);
+            if ((struct_ptr = get_structn(typename, typename_len)) == NULL) {
+                return false;
+            }
+            field_ptr = get_struct_fields_array(struct_ptr, &fields_count);
+            while (fields_count > 0) {
+                key = get_struct_field_keyname(field_ptr, &key_len);
+                if ((key_len == i) && (memcmp(key, path + offset, i) == 0)) {
+                    break;
+                }
+                field_ptr = get_next_struct_field(field_ptr);
+                fields_count -= 1;
+            }
+            if (fields_count == 0) {
+                return false;
+            }
+            offset += i;
+        } else {
+            return false;
+        }
+    }
+    return true;
 }
 
 /**
@@ -668,13 +760,15 @@ uint32_t get_path_crc(void) {
  */
 bool path_init(void) {
     if (path_struct == NULL) {
-        if ((path_struct = MEM_ALLOC_AND_ALIGN_TYPE(*path_struct)) == NULL) {
+        if (((path_struct = MEM_ALLOC_AND_ALIGN_TYPE(*path_struct)) == NULL) ||
+            ((path_backup = MEM_ALLOC_AND_ALIGN_TYPE(*path_backup)) == NULL)) {
             apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY;
         } else {
-            path_struct->depth_count = 0;
+            explicit_bzero(path_struct, sizeof(*path_struct));
+            explicit_bzero(path_backup, sizeof(*path_backup));
         }
     }
-    return path_struct != NULL;
+    return (path_struct != NULL) && (path_backup != NULL);
 }
 
 /**
diff --git a/src_features/signMessageEIP712/path.h b/src_features/signMessageEIP712/path.h
index fbb655eec..deb43ad39 100644
--- a/src_features/signMessageEIP712/path.h
+++ b/src_features/signMessageEIP712/path.h
@@ -28,16 +28,18 @@ typedef struct {
 
 bool path_set_root(const char *const struct_name, uint8_t length);
 const void *path_get_field(void);
-bool path_advance(bool array_check);
+bool path_advance(bool do_typehash);
 bool path_init(void);
 void path_deinit(void);
 bool path_new_array_depth(const uint8_t *const data, uint8_t length);
 e_root_type path_get_root_type(void);
 const void *path_get_root(void);
 const void *path_get_nth_field(uint8_t n);
+const void *path_backup_get_nth_field(uint8_t n);
+bool path_exists_in_backup(const char *path, size_t length);
 const void *path_get_nth_field_to_last(uint8_t n);
 uint8_t path_get_depth_count(void);
-uint32_t get_path_crc(void);
+uint8_t path_backup_get_depth_count(void);
 
 #endif  // HAVE_EIP712_FULL_SUPPORT
 
diff --git a/src_features/signMessageEIP712/type_hash.c b/src_features/signMessageEIP712/type_hash.c
index f37e20820..8318abcfd 100644
--- a/src_features/signMessageEIP712/type_hash.c
+++ b/src_features/signMessageEIP712/type_hash.c
@@ -129,7 +129,12 @@ static const void **get_struct_dependencies(uint8_t *const deps_count,
             // get struct name
             arg_structname = get_struct_field_typename(field_ptr, &arg_structname_length);
             // from its name, get the pointer to its definition
-            arg_struct_ptr = get_structn(arg_structname, arg_structname_length);
+            if ((arg_struct_ptr = get_structn(arg_structname, arg_structname_length)) == NULL) {
+                PRINTF("Error: could not find EIP-712 dependency struct \"");
+                for (int i = 0; i < arg_structname_length; ++i) PRINTF("%c", arg_structname[i]);
+                PRINTF("\" during type_hash\n");
+                return NULL;
+            }
 
             // check if it is not already present in the dependencies array
             for (dep_idx = 0; dep_idx < *deps_count; ++dep_idx) {
@@ -167,12 +172,18 @@ static const void **get_struct_dependencies(uint8_t *const deps_count,
  * @return whether the type_hash was successful or not
  */
 bool type_hash(const char *const struct_name, const uint8_t struct_name_length, uint8_t *hash_buf) {
-    const void *const struct_ptr = get_structn(struct_name, struct_name_length);
+    const void *struct_ptr;
     uint8_t deps_count = 0;
     const void **deps;
     void *mem_loc_bak = mem_alloc(0);
     cx_err_t error = CX_INTERNAL_ERROR;
 
+    if ((struct_ptr = get_structn(struct_name, struct_name_length)) == NULL) {
+        PRINTF("Error: could not find EIP-712 struct \"");
+        for (int i = 0; i < struct_name_length; ++i) PRINTF("%c", struct_name[i]);
+        PRINTF("\" for type_hash\n");
+        return false;
+    }
     CX_CHECK(cx_keccak_init_no_throw(&global_sha3, 256));
     deps = get_struct_dependencies(&deps_count, NULL, struct_ptr);
     if ((deps_count > 0) && (deps == NULL)) {
diff --git a/src_features/signMessageEIP712/ui_logic.c b/src_features/signMessageEIP712/ui_logic.c
index 5d698b1a4..da0c2c4c4 100644
--- a/src_features/signMessageEIP712/ui_logic.c
+++ b/src_features/signMessageEIP712/ui_logic.c
@@ -19,6 +19,7 @@
 #include "common_ui.h"
 #include "uint_common.h"
 #include "filtering.h"
+#include "trusted_name.h"
 
 #define AMOUNT_JOIN_FLAG_TOKEN (1 << 0)
 #define AMOUNT_JOIN_FLAG_VALUE (1 << 1)
@@ -42,6 +43,7 @@ typedef enum {
 #define UI_712_FIELD_NAME_PROVIDED (1 << 1)
 #define UI_712_AMOUNT_JOIN         (1 << 2)
 #define UI_712_DATETIME            (1 << 3)
+#define UI_712_TRUSTED_NAME        (1 << 4)
 
 typedef struct {
     s_amount_join joins[MAX_ASSETS];
@@ -52,13 +54,18 @@ typedef struct {
 typedef struct {
     bool shown;
     bool end_reached;
-    uint8_t filtering_mode;
+    e_eip712_filtering_mode filtering_mode;
     uint8_t filters_to_process;
     uint8_t field_flags;
     uint8_t structs_to_review;
     s_amount_context amount;
     uint8_t filters_received;
     uint32_t filters_crc[MAX_FILTERS];
+    uint8_t discarded_path_length;
+    char discarded_path[255];
+#ifdef HAVE_TRUSTED_NAME
+    e_name_type name_types;
+#endif
 #ifdef SCREEN_SIZE_WALLET
     char ui_pairs_buffer[(SHARED_CTX_FIELD_1_SIZE + SHARED_CTX_FIELD_2_SIZE) * 2];
 #endif
@@ -75,7 +82,11 @@ static bool ui_712_field_shown(void) {
     bool ret = false;
 
     if (ui_ctx->filtering_mode == EIP712_FILTERING_BASIC) {
+#ifdef SCREEN_SIZE_WALLET
+        if (true) {
+#else
         if (N_storage.verbose_eip712 || (path_get_root_type() == ROOT_DOMAIN)) {
+#endif
             ret = true;
         }
     } else {  // EIP712_FILTERING_FULL
@@ -146,14 +157,29 @@ void ui_712_set_value(const char *str, size_t length) {
 
 /**
  * Redraw the dynamic UI step that shows EIP712 information
+ *
+ * @return whether it was successful or not
  */
-void ui_712_redraw_generic_step(void) {
+bool ui_712_redraw_generic_step(void) {
     if (!ui_ctx->shown) {  // Initialize if it is not already
-        ui_712_start();
+        if ((ui_ctx->filtering_mode == EIP712_FILTERING_BASIC) && !N_storage.dataAllowed &&
+            !N_storage.verbose_eip712) {
+            // Both settings not enabled => Error
+            ui_error_blind_signing();
+            apdu_response_code = APDU_RESPONSE_INVALID_DATA;
+            eip712_context->go_home_on_failure = false;
+            return false;
+        }
+        if (ui_ctx->filtering_mode == EIP712_FILTERING_BASIC) {
+            ui_712_start_unfiltered();
+        } else {
+            ui_712_start();
+        }
         ui_ctx->shown = true;
     } else {
         ui_712_switch_to_message();
     }
+    return true;
 }
 
 /**
@@ -187,21 +213,22 @@ e_eip712_nfs ui_712_next_field(void) {
  * Used to notify of a new struct to review
  *
  * @param[in] struct_ptr pointer to the structure to be shown
+ * @return whether it was successful or not
  */
-void ui_712_review_struct(const void *struct_ptr) {
+bool ui_712_review_struct(const void *struct_ptr) {
     const char *struct_name;
     uint8_t struct_name_length;
     const char *title = "Review struct";
 
     if (ui_ctx == NULL) {
-        return;
+        return false;
     }
 
     ui_712_set_title(title, strlen(title));
     if ((struct_name = get_struct_name(struct_ptr, &struct_name_length)) != NULL) {
         ui_712_set_value(struct_name, struct_name_length);
     }
-    ui_712_redraw_generic_step();
+    return ui_712_redraw_generic_step();
 }
 
 /**
@@ -258,7 +285,8 @@ static bool ui_712_format_addr(const uint8_t *data, uint8_t length, bool first)
                                   strings.tmp.tmp,
                                   sizeof(strings.tmp.tmp),
                                   chainConfig->chainId)) {
-        THROW(APDU_RESPONSE_ERROR_NO_INFO);
+        apdu_response_code = APDU_RESPONSE_ERROR_NO_INFO;
+        return false;
     }
     return true;
 }
@@ -412,19 +440,21 @@ static bool ui_712_format_uint(const uint8_t *data, uint8_t length, bool first)
  * @return whether it was successful or not
  */
 static bool ui_712_format_amount_join(void) {
-    const tokenDefinition_t *token;
-    token = &tmpCtx.transactionContext.extraInfo[ui_ctx->amount.idx].token;
+    const tokenDefinition_t *token = NULL;
 
+    if (tmpCtx.transactionContext.assetSet[ui_ctx->amount.idx]) {
+        token = &tmpCtx.transactionContext.extraInfo[ui_ctx->amount.idx].token;
+    }
     if ((ui_ctx->amount.joins[ui_ctx->amount.idx].value_length == INT256_LENGTH) &&
         ismaxint(ui_ctx->amount.joins[ui_ctx->amount.idx].value,
                  ui_ctx->amount.joins[ui_ctx->amount.idx].value_length)) {
         strlcpy(strings.tmp.tmp, "Unlimited ", sizeof(strings.tmp.tmp));
-        strlcat(strings.tmp.tmp, token->ticker, sizeof(strings.tmp.tmp));
+        strlcat(strings.tmp.tmp, (token != NULL) ? token->ticker : "???", sizeof(strings.tmp.tmp));
     } else {
         if (!amountToString(ui_ctx->amount.joins[ui_ctx->amount.idx].value,
                             ui_ctx->amount.joins[ui_ctx->amount.idx].value_length,
-                            token->decimals,
-                            token->ticker,
+                            (token != NULL) ? token->decimals : 0,
+                            (token != NULL) ? token->ticker : "???",
                             strings.tmp.tmp,
                             sizeof(strings.tmp.tmp))) {
             return false;
@@ -453,13 +483,23 @@ void amount_join_set_token_received(void) {
  * @return whether it was successful or not
  */
 static bool update_amount_join(const uint8_t *data, uint8_t length) {
-    tokenDefinition_t *token;
+    const tokenDefinition_t *token = NULL;
 
-    token = &tmpCtx.transactionContext.extraInfo[ui_ctx->amount.idx].token;
+    if (tmpCtx.transactionContext.assetSet[ui_ctx->amount.idx]) {
+        token = &tmpCtx.transactionContext.extraInfo[ui_ctx->amount.idx].token;
+    } else {
+        if (tmpCtx.transactionContext.currentAssetIndex == ui_ctx->amount.idx) {
+            // So that the following amount-join find their tokens in the expected indices
+            tmpCtx.transactionContext.currentAssetIndex =
+                (tmpCtx.transactionContext.currentAssetIndex + 1) % MAX_ASSETS;
+        }
+    }
     switch (ui_ctx->amount.state) {
         case AMOUNT_JOIN_STATE_TOKEN:
-            if (memcmp(data, token->address, ADDRESS_LENGTH) != 0) {
-                return false;
+            if (token != NULL) {
+                if (memcmp(data, token->address, ADDRESS_LENGTH) != 0) {
+                    return false;
+                }
             }
             amount_join_set_token_received();
             break;
@@ -476,6 +516,37 @@ static bool update_amount_join(const uint8_t *data, uint8_t length) {
     return true;
 }
 
+#ifdef HAVE_TRUSTED_NAME
+/**
+ * Try to substitute given address by a matching contract name
+ *
+ * Fallback on showing the address if no match is found.
+ *
+ * @param[in] data the data that needs formatting
+ * @param[in] length its length
+ * @return whether it was successful or not
+ */
+static bool ui_712_format_trusted_name(const uint8_t *data, uint8_t length) {
+    uint8_t types_count = 0;
+    e_name_type types[8];
+    uint8_t types_bak = ui_ctx->name_types;
+
+    if (length != ADDRESS_LENGTH) {
+        return false;
+    }
+    for (int i = 0; types_bak > 0; ++i) {
+        if (types_bak & 1) {
+            types[types_count++] = i;
+        }
+        types_bak >>= 1;
+    }
+    if (has_trusted_name(types_count, types, &eip712_context->chain_id, data)) {
+        strlcpy(strings.tmp.tmp, g_trusted_name, sizeof(strings.tmp.tmp));
+    }
+    return true;
+}
+#endif
+
 /**
  * Format given data as a human-readable date/time representation
  *
@@ -591,9 +662,17 @@ bool ui_712_feed_to_display(const void *field_ptr,
         }
     }
 
+#ifdef HAVE_TRUSTED_NAME
+    if (ui_ctx->field_flags & UI_712_TRUSTED_NAME) {
+        if (!ui_712_format_trusted_name(data, length)) {
+            return false;
+        }
+    }
+#endif
+
     // Check if this field is supposed to be displayed
     if (last && ui_712_field_shown()) {
-        ui_712_redraw_generic_step();
+        if (!ui_712_redraw_generic_step()) return false;
     }
     return true;
 }
@@ -608,7 +687,11 @@ void ui_712_end_sign(void) {
         return;
     }
 
+#ifdef SCREEN_SIZE_WALLET
+    if (true) {
+#else
     if (N_storage.verbose_eip712 || (ui_ctx->filtering_mode == EIP712_FILTERING_FULL)) {
+#endif
         ui_ctx->end_reached = true;
         ui_712_switch_to_sign();
     }
@@ -667,8 +750,13 @@ unsigned int ui_712_reject() {
  * @param[in] name_provided if a substitution name has been provided
  * @param[in] token_join if this field is part of a token join
  * @param[in] datetime if this field should be shown and formatted as a date/time
+ * @param[in] trusted_name if this field should be shown as a trusted contract name
  */
-void ui_712_flag_field(bool show, bool name_provided, bool token_join, bool datetime) {
+void ui_712_flag_field(bool show,
+                       bool name_provided,
+                       bool token_join,
+                       bool datetime,
+                       bool trusted_name) {
     if (show) {
         ui_ctx->field_flags |= UI_712_FIELD_SHOWN;
     }
@@ -681,6 +769,9 @@ void ui_712_flag_field(bool show, bool name_provided, bool token_join, bool date
     if (datetime) {
         ui_ctx->field_flags |= UI_712_DATETIME;
     }
+    if (trusted_name) {
+        ui_ctx->field_flags |= UI_712_TRUSTED_NAME;
+    }
 }
 
 /**
@@ -732,7 +823,11 @@ void ui_712_field_flags_reset(void) {
  * Makes it so the user will have to go through a "Review struct" screen
  */
 void ui_712_queue_struct_to_review(void) {
+#ifdef SCREEN_SIZE_WALLET
+    if (true) {
+#else
     if (N_storage.verbose_eip712) {
+#endif
         ui_ctx->structs_to_review += 1;
     }
 }
@@ -787,11 +882,10 @@ bool ui_712_show_raw_key(const void *field_ptr) {
 /**
  * Push a new filter path
  *
+ * @param[in] path_crc CRC of the filter path
  * @return if the path was pushed or not (in case it was already present)
  */
-bool ui_712_push_new_filter_path(void) {
-    uint32_t path_crc = get_path_crc();
-
+bool ui_712_push_new_filter_path(uint32_t path_crc) {
     // check if already present
     for (int i = 0; i < ui_ctx->filters_received; ++i) {
         if (ui_ctx->filters_crc[i] == path_crc) {
@@ -804,6 +898,38 @@ bool ui_712_push_new_filter_path(void) {
     return true;
 }
 
+/**
+ * Set a discarded filter path
+ *
+ * @param[in] path the given filter path
+ * @param[in] length the path length
+ */
+void ui_712_set_discarded_path(const char *path, uint8_t length) {
+    memcpy(ui_ctx->discarded_path, path, length);
+    ui_ctx->discarded_path_length = length;
+}
+
+/**
+ * Get the discarded filter path
+ *
+ * @param[out] length the path length
+ * @return filter path
+ */
+const char *ui_712_get_discarded_path(uint8_t *length) {
+    *length = ui_ctx->discarded_path_length;
+    return ui_ctx->discarded_path;
+}
+
+#ifdef HAVE_TRUSTED_NAME
+void ui_712_set_trusted_name_requirements(uint8_t types_count, const e_name_type *types) {
+    // pack into one byte to save on space
+    ui_ctx->name_types = 0;
+    for (int i = 0; i < types_count; ++i) {
+        ui_ctx->name_types |= (1 << types[i]);
+    }
+}
+#endif
+
 #ifdef SCREEN_SIZE_WALLET
 /*
  * Get UI pairs buffer
diff --git a/src_features/signMessageEIP712/ui_logic.h b/src_features/signMessageEIP712/ui_logic.h
index 9ce4ee152..d64e47f32 100644
--- a/src_features/signMessageEIP712/ui_logic.h
+++ b/src_features/signMessageEIP712/ui_logic.h
@@ -6,6 +6,7 @@
 #include <stdint.h>
 #include "ux.h"
 #include "uint256.h"
+#include "trusted_name.h"
 
 typedef enum { EIP712_FILTERING_BASIC, EIP712_FILTERING_FULL } e_eip712_filtering_mode;
 typedef enum {
@@ -17,7 +18,7 @@ typedef enum {
 bool ui_712_init(void);
 void ui_712_deinit(void);
 e_eip712_nfs ui_712_next_field(void);
-void ui_712_review_struct(const void *const struct_ptr);
+bool ui_712_review_struct(const void *const struct_ptr);
 bool ui_712_feed_to_display(const void *field_ptr,
                             const uint8_t *data,
                             uint8_t length,
@@ -29,8 +30,12 @@ unsigned int ui_712_reject();
 void ui_712_set_title(const char *str, size_t length);
 void ui_712_set_value(const char *str, size_t length);
 void ui_712_message_hash(void);
-void ui_712_redraw_generic_step(void);
-void ui_712_flag_field(bool show, bool name_provided, bool token_join, bool datetime);
+bool ui_712_redraw_generic_step(void);
+void ui_712_flag_field(bool show,
+                       bool name_provided,
+                       bool token_join,
+                       bool datetime,
+                       bool contract_name);
 void ui_712_field_flags_reset(void);
 void ui_712_finalize_field(void);
 void ui_712_set_filtering_mode(e_eip712_filtering_mode mode);
@@ -43,7 +48,12 @@ void ui_712_token_join_prepare_addr_check(uint8_t index);
 void ui_712_token_join_prepare_amount(uint8_t index, const char *name, uint8_t name_length);
 void amount_join_set_token_received(void);
 bool ui_712_show_raw_key(const void *field_ptr);
-bool ui_712_push_new_filter_path(void);
+bool ui_712_push_new_filter_path(uint32_t path_crc);
+void ui_712_set_discarded_path(const char *path, uint8_t length);
+const char *ui_712_get_discarded_path(uint8_t *length);
+#ifdef HAVE_TRUSTED_NAME
+void ui_712_set_trusted_name_requirements(uint8_t types_count, const e_name_type *types);
+#endif
 #ifdef SCREEN_SIZE_WALLET
 char *get_ui_pairs_buffer(size_t *size);
 #endif
diff --git a/src_features/signMessageEIP712_common/common_712.c b/src_features/signMessageEIP712_common/common_712.c
index 95b8866d5..bdf64cbd1 100644
--- a/src_features/signMessageEIP712_common/common_712.c
+++ b/src_features/signMessageEIP712_common/common_712.c
@@ -11,7 +11,6 @@ static const uint8_t EIP_712_MAGIC[] = {0x19, 0x01};
 
 unsigned int ui_712_approve_cb(void) {
     uint8_t hash[INT256_LENGTH];
-    uint32_t tx = 0;
 
     io_seproxyhal_io_heartbeat();
     CX_ASSERT(cx_keccak_init_no_throw(&global_sha3, 256));
@@ -37,18 +36,16 @@ unsigned int ui_712_approve_cb(void) {
     PRINTF("EIP712 Message hash 0x%.*h\n", 32, tmpCtx.messageSigningContext712.messageHash);
 
     unsigned int info = 0;
-    if (bip32_derive_ecdsa_sign_rs_hash_256(CX_CURVE_256K1,
-                                            tmpCtx.messageSigningContext712.bip32.path,
-                                            tmpCtx.messageSigningContext712.bip32.length,
-                                            CX_RND_RFC6979 | CX_LAST,
-                                            CX_SHA256,
-                                            hash,
-                                            sizeof(hash),
-                                            G_io_apdu_buffer + 1,
-                                            G_io_apdu_buffer + 1 + 32,
-                                            &info) != CX_OK) {
-        THROW(APDU_RESPONSE_UNKNOWN);
-    }
+    CX_ASSERT(bip32_derive_ecdsa_sign_rs_hash_256(CX_CURVE_256K1,
+                                                  tmpCtx.messageSigningContext712.bip32.path,
+                                                  tmpCtx.messageSigningContext712.bip32.length,
+                                                  CX_RND_RFC6979 | CX_LAST,
+                                                  CX_SHA256,
+                                                  hash,
+                                                  sizeof(hash),
+                                                  G_io_apdu_buffer + 1,
+                                                  G_io_apdu_buffer + 1 + 32,
+                                                  &info));
     G_io_apdu_buffer[0] = 27;
     if (info & CX_ECCINFO_PARITY_ODD) {
         G_io_apdu_buffer[0]++;
@@ -56,24 +53,9 @@ unsigned int ui_712_approve_cb(void) {
     if (info & CX_ECCINFO_xGTn) {
         G_io_apdu_buffer[0] += 2;
     }
-    tx = 65;
-    G_io_apdu_buffer[tx++] = 0x90;
-    G_io_apdu_buffer[tx++] = 0x00;
-    reset_app_context();
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+    return io_seproxyhal_send_status(APDU_RESPONSE_OK, 65, true, false);
 }
 
 unsigned int ui_712_reject_cb(void) {
-    reset_app_context();
-    G_io_apdu_buffer[0] = 0x69;
-    G_io_apdu_buffer[1] = 0x85;
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+    return io_seproxyhal_send_status(APDU_RESPONSE_CONDITION_NOT_SATISFIED, 0, true, false);
 }
diff --git a/src_features/signMessageEIP712_v0/cmd_signMessage712.c b/src_features/signMessageEIP712_v0/cmd_signMessage712.c
index d9587e67f..844a3c8fc 100644
--- a/src_features/signMessageEIP712_v0/cmd_signMessage712.c
+++ b/src_features/signMessageEIP712_v0/cmd_signMessage712.c
@@ -4,25 +4,24 @@
 #include "common_ui.h"
 #include "common_712.h"
 
-void handleSignEIP712Message_v0(uint8_t p1,
-                                uint8_t p2,
-                                const uint8_t *workBuffer,
-                                uint8_t dataLength,
-                                unsigned int *flags,
-                                unsigned int *tx) {
-    (void) tx;
-    (void) p2;
-    if (p1 != 00) {
-        THROW(APDU_RESPONSE_INVALID_P1_P2);
+uint16_t handleSignEIP712Message_v0(uint8_t p1,
+                                    const uint8_t *workBuffer,
+                                    uint8_t dataLength,
+                                    unsigned int *flags) {
+    if (p1 != 0x00) {
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
     if (appState != APP_STATE_IDLE) {
         reset_app_context();
     }
 
+    if (!N_storage.dataAllowed) {
+        ui_error_blind_signing();
+        return APDU_RESPONSE_INVALID_DATA;
+    }
     workBuffer = parseBip32(workBuffer, &dataLength, &tmpCtx.messageSigningContext.bip32);
-
     if ((workBuffer == NULL) || (dataLength < (KECCAK256_HASH_BYTESIZE * 2))) {
-        THROW(APDU_RESPONSE_INVALID_DATA);
+        return APDU_RESPONSE_INVALID_DATA;
     }
     memmove(tmpCtx.messageSigningContext712.domainHash, workBuffer, KECCAK256_HASH_BYTESIZE);
     memmove(tmpCtx.messageSigningContext712.messageHash,
@@ -32,4 +31,5 @@ void handleSignEIP712Message_v0(uint8_t p1,
     ui_sign_712_v0();
 
     *flags |= IO_ASYNCH_REPLY;
+    return APDU_NO_RESPONSE;
 }
diff --git a/src_features/signTx/cmd_signTx.c b/src_features/signTx/cmd_signTx.c
index 99ac51f49..f4ecbada9 100644
--- a/src_features/signTx/cmd_signTx.c
+++ b/src_features/signTx/cmd_signTx.c
@@ -3,18 +3,18 @@
 #include "feature_signTx.h"
 #include "eth_plugin_interface.h"
 
-void handleSign(uint8_t p1,
-                uint8_t p2,
-                const uint8_t *workBuffer,
-                uint8_t dataLength,
-                unsigned int *flags,
-                unsigned int *tx) {
-    UNUSED(tx);
+uint16_t handleSign(uint8_t p1,
+                    uint8_t p2,
+                    const uint8_t *workBuffer,
+                    uint8_t dataLength,
+                    unsigned int *flags) {
     parserStatus_e txResult;
+    uint16_t sw = APDU_NO_RESPONSE;
+    cx_err_t error = CX_INTERNAL_ERROR;
 
     if (os_global_pin_is_validated() != BOLOS_UX_OK) {
         PRINTF("Device is PIN-locked");
-        THROW(0x6982);
+        return APDU_RESPONSE_SECURITY_NOT_SATISFIED;
     }
     if (p1 == P1_FIRST) {
         if (appState != APP_STATE_IDLE) {
@@ -23,19 +23,20 @@ void handleSign(uint8_t p1,
         appState = APP_STATE_SIGNING_TX;
 
         workBuffer = parseBip32(workBuffer, &dataLength, &tmpCtx.transactionContext.bip32);
-
         if (workBuffer == NULL) {
-            THROW(0x6a80);
+            return APDU_RESPONSE_INVALID_DATA;
         }
 
         tmpContent.txContent.dataPresent = false;
         dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_UNAVAILABLE;
 
-        initTx(&txContext, &global_sha3, &tmpContent.txContent, customProcessor, NULL);
-
+        if (initTx(&txContext, &global_sha3, &tmpContent.txContent, customProcessor, NULL) ==
+            false) {
+            return APDU_RESPONSE_INVALID_DATA;
+        }
         if (dataLength < 1) {
             PRINTF("Invalid data\n");
-            THROW(0x6a80);
+            return APDU_RESPONSE_INVALID_DATA;
         }
 
         // EIP 2718: TransactionType might be present before the TransactionPayload.
@@ -43,50 +44,52 @@ void handleSign(uint8_t p1,
         if (txType >= MIN_TX_TYPE && txType <= MAX_TX_TYPE) {
             // Enumerate through all supported txTypes here...
             if (txType == EIP2930 || txType == EIP1559) {
-                CX_ASSERT(cx_hash_no_throw((cx_hash_t *) &global_sha3, 0, workBuffer, 1, NULL, 0));
+                error = cx_hash_no_throw((cx_hash_t *) &global_sha3, 0, workBuffer, 1, NULL, 0);
+                if (error != CX_OK) {
+                    return error;
+                }
                 txContext.txType = txType;
                 workBuffer++;
                 dataLength--;
             } else {
                 PRINTF("Transaction type %d not supported\n", txType);
-                THROW(0x6501);
+                return APDU_RESPONSE_TX_TYPE_NOT_SUPPORTED;
             }
         } else {
             txContext.txType = LEGACY;
         }
         PRINTF("TxType: %x\n", txContext.txType);
     } else if (p1 != P1_MORE) {
-        THROW(0x6B00);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
     if (p2 != 0) {
-        THROW(0x6B00);
+        return APDU_RESPONSE_INVALID_P1_P2;
     }
     if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_TX)) {
         PRINTF("Signature not initialized\n");
-        THROW(0x6985);
+        return APDU_RESPONSE_CONDITION_NOT_SATISFIED;
     }
     if (txContext.currentField == RLP_NONE) {
         PRINTF("Parser not initialized\n");
-        THROW(0x6985);
+        return APDU_RESPONSE_CONDITION_NOT_SATISFIED;
     }
     txResult = processTx(&txContext, workBuffer, dataLength);
     switch (txResult) {
         case USTREAM_SUSPENDED:
             break;
         case USTREAM_FINISHED:
+            sw = finalizeParsing();
             break;
         case USTREAM_PROCESSING:
-            THROW(0x9000);
+            return APDU_RESPONSE_OK;
         case USTREAM_FAULT:
-            THROW(0x6A80);
+            return APDU_RESPONSE_INVALID_DATA;
         default:
             PRINTF("Unexpected parser status\n");
-            THROW(0x6A80);
-    }
-
-    if (txResult == USTREAM_FINISHED) {
-        finalizeParsing();
+            return APDU_RESPONSE_INVALID_DATA;
     }
 
     *flags |= IO_ASYNCH_REPLY;
+    // Return code will be sent after UI approve/cancel
+    return sw;
 }
diff --git a/src_features/signTx/feature_signTx.h b/src_features/signTx/feature_signTx.h
index a62514a47..ace67f0ae 100644
--- a/src_features/signTx/feature_signTx.h
+++ b/src_features/signTx/feature_signTx.h
@@ -11,11 +11,8 @@ typedef enum {
 } plugin_ui_state_t;
 
 customStatus_e customProcessor(txContext_t *context);
-void finalizeParsing();
-void prepareFeeDisplay();
-void prepareNetworkDisplay();
+uint16_t finalizeParsing();
 void ux_approve_tx(bool fromPlugin);
-void report_finalize_error(void);
 void start_signature_flow(void);
 
 #endif  // _SIGN_TX_H_
diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c
index 513f704ef..55690e5fc 100644
--- a/src_features/signTx/logic_signTx.c
+++ b/src_features/signTx/logic_signTx.c
@@ -12,8 +12,6 @@
 #include "format.h"
 #include "manage_asset_info.h"
 
-#define ERR_SILENT_MODE_CHECK_FAILED 0x6001
-
 static bool g_use_standard_ui;
 
 static uint32_t splitBinaryParameterPart(char *result, size_t result_size, uint8_t *parameter) {
@@ -74,7 +72,9 @@ customStatus_e customProcessor(txContext_t *context) {
             } else if (status >= ETH_PLUGIN_RESULT_SUCCESSFUL) {
                 dataContext.tokenContext.fieldIndex = 0;
                 dataContext.tokenContext.fieldOffset = 0;
-                copyTxData(context, NULL, 4);
+                if (copyTxData(context, NULL, 4) == false) {
+                    return CUSTOM_FAULT;
+                }
                 if (context->currentFieldLength == 4) {
                     return CUSTOM_NOT_HANDLED;
                 }
@@ -113,9 +113,11 @@ customStatus_e customProcessor(txContext_t *context) {
 
         PRINTF("currentFieldPos %d copySize %d\n", context->currentFieldPos, copySize);
 
-        copyTxData(context,
-                   dataContext.tokenContext.data + dataContext.tokenContext.fieldOffset,
-                   copySize);
+        if (copyTxData(context,
+                       dataContext.tokenContext.data + dataContext.tokenContext.fieldOffset,
+                       copySize) == false) {
+            return CUSTOM_FAULT;
+        }
 
         if (context->currentFieldPos == context->currentFieldLength) {
             PRINTF("\n\nIncrementing one\n");
@@ -179,24 +181,23 @@ customStatus_e customProcessor(txContext_t *context) {
     return CUSTOM_NOT_HANDLED;
 }
 
-void report_finalize_error(void) {
-    reset_app_context();
-    io_seproxyhal_send_status(APDU_RESPONSE_INVALID_DATA);
-    ui_idle();
+static void report_finalize_error(void) {
+    io_seproxyhal_send_status(APDU_RESPONSE_INVALID_DATA, 0, true, true);
 }
 
-static void address_to_string(uint8_t *in,
-                              size_t in_len,
-                              char *out,
-                              size_t out_len,
-                              uint64_t chainId) {
+static uint16_t address_to_string(uint8_t *in,
+                                  size_t in_len,
+                                  char *out,
+                                  size_t out_len,
+                                  uint64_t chainId) {
     if (in_len != 0) {
         if (!getEthDisplayableAddress(in, out, out_len, chainId)) {
-            THROW(APDU_RESPONSE_ERROR_NO_INFO);
+            return APDU_RESPONSE_ERROR_NO_INFO;
         }
     } else {
         strlcpy(out, "Contract", out_len);
     }
+    return APDU_RESPONSE_OK;
 }
 
 static void raw_fee_to_string(uint256_t *rawFee, char *displayBuffer, uint32_t displayBufferSize) {
@@ -243,7 +244,7 @@ static void raw_fee_to_string(uint256_t *rawFee, char *displayBuffer, uint32_t d
 
 // Compute the fees, transform it to a string, prepend a ticker to it and copy everything to
 // `displayBuffer` output
-static void max_transaction_fee_to_string(const txInt256_t *BEGasPrice,
+static bool max_transaction_fee_to_string(const txInt256_t *BEGasPrice,
                                           const txInt256_t *BEGasLimit,
                                           char *displayBuffer,
                                           uint32_t displayBufferSize) {
@@ -257,8 +258,11 @@ static void max_transaction_fee_to_string(const txInt256_t *BEGasPrice,
     PRINTF("Gas limit %.*H\n", BEGasLimit->length, BEGasLimit->value);
     convertUint256BE(BEGasPrice->value, BEGasPrice->length, &gasPrice);
     convertUint256BE(BEGasLimit->value, BEGasLimit->length, &gasLimit);
-    mul256(&gasPrice, &gasLimit, &rawFee);
+    if (mul256(&gasPrice, &gasLimit, &rawFee) == false) {
+        return false;
+    }
     raw_fee_to_string(&rawFee, displayBuffer, displayBufferSize);
+    return true;
 }
 
 static void nonce_to_string(const txInt256_t *nonce, char *out, size_t out_size) {
@@ -267,37 +271,40 @@ static void nonce_to_string(const txInt256_t *nonce, char *out, size_t out_size)
     tostring256(&nonce_uint256, 10, out, out_size);
 }
 
-static void get_network_as_string(char *out, size_t out_size) {
+static uint16_t get_network_as_string(char *out, size_t out_size) {
     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.
         if (!u64_to_string(chain_id, out, out_size)) {
-            THROW(0x6502);
+            return APDU_RESPONSE_CHAINID_OUT_BUF_SMALL;
         }
     } else {
         // Network name found, simply copy it.
         strlcpy(out, name, out_size);
     }
+    return APDU_RESPONSE_OK;
 }
 
-static void get_public_key(uint8_t *out, uint8_t outLength) {
+static uint16_t get_public_key(uint8_t *out, uint8_t outLength) {
     uint8_t raw_pubkey[65];
+    cx_err_t error = CX_INTERNAL_ERROR;
 
     if (outLength < ADDRESS_LENGTH) {
-        return;
-    }
-    if (bip32_derive_get_pubkey_256(CX_CURVE_256K1,
-                                    tmpCtx.transactionContext.bip32.path,
-                                    tmpCtx.transactionContext.bip32.length,
-                                    raw_pubkey,
-                                    NULL,
-                                    CX_SHA512) != CX_OK) {
-        THROW(APDU_RESPONSE_UNKNOWN);
+        return APDU_RESPONSE_WRONG_DATA_LENGTH;
     }
+    CX_CHECK(bip32_derive_get_pubkey_256(CX_CURVE_256K1,
+                                         tmpCtx.transactionContext.bip32.path,
+                                         tmpCtx.transactionContext.bip32.length,
+                                         raw_pubkey,
+                                         NULL,
+                                         CX_SHA512));
 
     getEthAddressFromRawKey(raw_pubkey, out);
+    error = APDU_RESPONSE_OK;
+end:
+    return error;
 }
 
 /* Local implementation of strncasecmp, workaround of the segfaulting base implem
@@ -315,7 +322,7 @@ static int strcasecmp_workaround(const char *str1, const char *str2) {
     return 0;
 }
 
-__attribute__((noinline)) static bool finalize_parsing_helper(void) {
+__attribute__((noinline)) static uint16_t finalize_parsing_helper(void) {
     char displayBuffer[50];
     uint8_t decimals = WEI_TO_ETHER;
     uint64_t chain_id = get_tx_chain_id();
@@ -329,9 +336,8 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
 
         if (chainConfig->chainId != id) {
             PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId);
-            reset_app_context();
             report_finalize_error();
-            return false;
+            return APDU_NO_RESPONSE;
         }
     }
     // Store the hash
@@ -343,13 +349,19 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
                               32));
 
     uint8_t msg_sender[ADDRESS_LENGTH] = {0};
-    get_public_key(msg_sender, sizeof(msg_sender));
+    error = get_public_key(msg_sender, sizeof(msg_sender));
+    if (error != APDU_RESPONSE_OK) {
+        goto end;
+    }
 
-    address_to_string(msg_sender,
-                      ADDRESS_LENGTH,
-                      strings.common.fromAddress,
-                      sizeof(strings.common.fromAddress),
-                      chainConfig->chainId);
+    error = address_to_string(msg_sender,
+                              ADDRESS_LENGTH,
+                              strings.common.fromAddress,
+                              sizeof(strings.common.fromAddress),
+                              chainConfig->chainId);
+    if (error != APDU_RESPONSE_OK) {
+        goto end;
+    }
     PRINTF("FROM address displayed: %s\n", strings.common.fromAddress);
     // Finalize the plugin handling
     if (dataContext.tokenContext.pluginStatus >= ETH_PLUGIN_RESULT_SUCCESSFUL) {
@@ -360,7 +372,7 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
         if (!eth_plugin_call(ETH_PLUGIN_FINALIZE, (void *) &pluginFinalize)) {
             PRINTF("Plugin finalize call failed\n");
             report_finalize_error();
-            return false;
+            return APDU_NO_RESPONSE;
         }
         // Lookup tokens if requested
         ethPluginProvideInfo_t pluginProvideInfo;
@@ -384,11 +396,12 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
                 ETH_PLUGIN_RESULT_UNSUCCESSFUL) {
                 PRINTF("Plugin provide token call failed\n");
                 report_finalize_error();
-                return false;
+                return APDU_NO_RESPONSE;
             }
             pluginFinalize.result = pluginProvideInfo.result;
         }
         if (pluginFinalize.result != ETH_PLUGIN_RESULT_FALLBACK) {
+            PRINTF("pluginFinalize.result %d successful\n", pluginFinalize.result);
             // Handle the right interface
             switch (pluginFinalize.uiType) {
                 case ETH_UI_TYPE_GENERIC:
@@ -407,7 +420,7 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
                     if ((pluginFinalize.amount == NULL) || (pluginFinalize.address == NULL)) {
                         PRINTF("Incorrect amount/address set by plugin\n");
                         report_finalize_error();
-                        return false;
+                        return APDU_NO_RESPONSE;
                     }
                     memmove(tmpContent.txContent.value.value, pluginFinalize.amount, 32);
                     tmpContent.txContent.value.length = 32;
@@ -421,8 +434,12 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
                 default:
                     PRINTF("ui type %d not supported\n", pluginFinalize.uiType);
                     report_finalize_error();
-                    return false;
+                    return APDU_NO_RESPONSE;
             }
+        } else if (G_called_from_swap && G_swap_mode == SWAP_MODE_CROSSCHAIN_SUCCESS) {
+            PRINTF("Plugin swap_with_calldata fell back for UI with success\n");
+            // We are not bling signing, the data has been validated by the plugin
+            tmpContent.txContent.dataPresent = false;
         }
     }
 
@@ -430,18 +447,29 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
         if (G_swap_response_ready) {
             // Unreachable given current return to exchange mechanism. Safeguard against regression
             PRINTF("FATAL: safety against double sign triggered\n");
-            os_sched_exit(-1);
+            app_exit();
         }
         G_swap_response_ready = true;
     }
 
     // User has just validated a swap but ETH received apdus about a non standard plugin / contract
     if (G_called_from_swap && !g_use_standard_ui) {
-        PRINTF("ERR_SILENT_MODE_CHECK_FAILED, G_called_from_swap\n");
-        THROW(ERR_SILENT_MODE_CHECK_FAILED);
+        PRINTF("APDU_RESPONSE_MODE_CHECK_FAILED, G_called_from_swap\n");
+        return APDU_RESPONSE_MODE_CHECK_FAILED;
+    }
+
+    // Specific calldata check when in swap mode
+    if (G_called_from_swap) {
+        // Two success cases: we are in standard mode and no calldata was received
+        // We are in crosschain mode and the correct calldata has been received
+        if (G_swap_mode != SWAP_MODE_STANDARD && G_swap_mode != SWAP_MODE_CROSSCHAIN_SUCCESS) {
+            PRINTF("Error: G_swap_mode %d refused\n", G_swap_mode);
+            return APDU_RESPONSE_MODE_CHECK_FAILED;
+        }
     }
 
     if (tmpContent.txContent.dataPresent && !N_storage.dataAllowed) {
+        PRINTF("Data is present but not allowed\n");
         report_finalize_error();
         ui_error_blind_signing();
         return false;
@@ -451,16 +479,19 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
     if (g_use_standard_ui) {
         // Format the address in a temporary buffer, if in swap case compare it with validated
         // address, else commit it
-        address_to_string(tmpContent.txContent.destination,
-                          tmpContent.txContent.destinationLength,
-                          displayBuffer,
-                          sizeof(displayBuffer),
-                          chainConfig->chainId);
+        error = address_to_string(tmpContent.txContent.destination,
+                                  tmpContent.txContent.destinationLength,
+                                  displayBuffer,
+                                  sizeof(displayBuffer),
+                                  chainConfig->chainId);
+        if (error != APDU_RESPONSE_OK) {
+            goto end;
+        }
         if (G_called_from_swap) {
             // Ensure the values are the same that the ones that have been previously validated
             if (strcasecmp_workaround(strings.common.toAddress, displayBuffer) != 0) {
-                PRINTF("ERR_SILENT_MODE_CHECK_FAILED, address check failed\n");
-                THROW(ERR_SILENT_MODE_CHECK_FAILED);
+                PRINTF("APDU_RESPONSE_MODE_CHECK_FAILED, address check failed\n");
+                return APDU_RESPONSE_MODE_CHECK_FAILED;
             }
         } else {
             strlcpy(strings.common.toAddress, displayBuffer, sizeof(strings.common.toAddress));
@@ -476,16 +507,16 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
                             displayBuffer,
                             sizeof(displayBuffer))) {
             PRINTF("OVERFLOW, amount to string failed\n");
-            THROW(EXCEPTION_OVERFLOW);
+            return EXCEPTION_OVERFLOW;
         }
 
         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");
+                PRINTF("APDU_RESPONSE_MODE_CHECK_FAILED, amount check failed\n");
                 PRINTF("Expected %s\n", strings.common.fullAmount);
                 PRINTF("Received %s\n", displayBuffer);
-                THROW(ERR_SILENT_MODE_CHECK_FAILED);
+                return APDU_RESPONSE_MODE_CHECK_FAILED;
             }
         } else {
             strlcpy(strings.common.fullAmount, displayBuffer, sizeof(strings.common.fullAmount));
@@ -495,17 +526,19 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
 
     // Compute the max fee in a temporary buffer, if in swap case compare it with validated max fee,
     // else commit it
-    max_transaction_fee_to_string(&tmpContent.txContent.gasprice,
-                                  &tmpContent.txContent.startgas,
-                                  displayBuffer,
-                                  sizeof(displayBuffer));
+    if (max_transaction_fee_to_string(&tmpContent.txContent.gasprice,
+                                      &tmpContent.txContent.startgas,
+                                      displayBuffer,
+                                      sizeof(displayBuffer)) == false) {
+        return APDU_RESPONSE_INVALID_DATA;
+    }
     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");
+            PRINTF("APDU_RESPONSE_MODE_CHECK_FAILED, fees check failed\n");
             PRINTF("Expected %s\n", strings.common.maxFee);
             PRINTF("Received %s\n", displayBuffer);
-            THROW(ERR_SILENT_MODE_CHECK_FAILED);
+            return APDU_RESPONSE_MODE_CHECK_FAILED;
         }
     } else {
         strlcpy(strings.common.maxFee, displayBuffer, sizeof(strings.common.maxFee));
@@ -520,11 +553,12 @@ __attribute__((noinline)) static bool finalize_parsing_helper(void) {
     PRINTF("Nonce: %s\n", strings.common.nonce);
 
     // Prepare network field
-    get_network_as_string(strings.common.network_name, sizeof(strings.common.network_name));
-    PRINTF("Network: %s\n", strings.common.network_name);
-    return true;
+    error = get_network_as_string(strings.common.network_name, sizeof(strings.common.network_name));
+    if (error == APDU_RESPONSE_OK) {
+        PRINTF("Network: %s\n", strings.common.network_name);
+    }
 end:
-    return false;
+    return error;
 }
 
 void start_signature_flow(void) {
@@ -537,22 +571,29 @@ void start_signature_flow(void) {
     }
 }
 
-void finalizeParsing(void) {
+uint16_t finalizeParsing(void) {
+    uint16_t sw = APDU_RESPONSE_UNKNOWN;
     g_use_standard_ui = true;
 
-    if (!finalize_parsing_helper()) {
-        return;
+    sw = finalize_parsing_helper();
+    if (sw != APDU_RESPONSE_OK) {
+        return sw;
     }
     // If called from swap, the user has already validated a standard transaction
     // And we have already checked the fields of this transaction above
     if (G_called_from_swap && g_use_standard_ui) {
-        io_seproxyhal_touch_tx_ok(NULL);
+        ui_idle();
+        io_seproxyhal_touch_tx_ok();
     } else {
+#ifdef HAVE_BAGL
         // If blind-signing detected, start the warning flow beforehand
         if (tmpContent.txContent.dataPresent) {
             ui_warning_blind_signing();
-        } else {
+        } else
+#endif
+        {
             start_signature_flow();
         }
     }
+    return APDU_RESPONSE_OK;
 }
diff --git a/src_features/signTx/ui_common_signTx.c b/src_features/signTx/ui_common_signTx.c
index 4b567db5b..c29f3672e 100644
--- a/src_features/signTx/ui_common_signTx.c
+++ b/src_features/signTx/ui_common_signTx.c
@@ -5,22 +5,21 @@
 #include "common_ui.h"
 #include "handle_swap_sign_transaction.h"
 #include "feature_signTx.h"
+#include "apdu_constants.h"
 
-unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_element_t *e) {
+uint32_t io_seproxyhal_touch_tx_ok(void) {
     uint32_t info = 0;
-    int err;
-    if (bip32_derive_ecdsa_sign_rs_hash_256(CX_CURVE_256K1,
-                                            tmpCtx.transactionContext.bip32.path,
-                                            tmpCtx.transactionContext.bip32.length,
-                                            CX_RND_RFC6979 | CX_LAST,
-                                            CX_SHA256,
-                                            tmpCtx.transactionContext.hash,
-                                            sizeof(tmpCtx.transactionContext.hash),
-                                            G_io_apdu_buffer + 1,
-                                            G_io_apdu_buffer + 1 + 32,
-                                            &info) != CX_OK) {
-        THROW(0x6F00);
-    }
+    int err = 0;
+    CX_ASSERT(bip32_derive_ecdsa_sign_rs_hash_256(CX_CURVE_256K1,
+                                                  tmpCtx.transactionContext.bip32.path,
+                                                  tmpCtx.transactionContext.bip32.length,
+                                                  CX_RND_RFC6979 | CX_LAST,
+                                                  CX_SHA256,
+                                                  tmpCtx.transactionContext.hash,
+                                                  sizeof(tmpCtx.transactionContext.hash),
+                                                  G_io_apdu_buffer + 1,
+                                                  G_io_apdu_buffer + 1 + 32,
+                                                  &info));
 
     if (txContext.txType == EIP1559 || txContext.txType == EIP2930) {
         if (info & CX_ECCINFO_PARITY_ODD) {
@@ -52,11 +51,8 @@ unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_elemen
     }
 
     // Write status code at parity_byte + r + s
-    G_io_apdu_buffer[1 + 64] = 0x90;
-    G_io_apdu_buffer[1 + 64 + 1] = 0x00;
-
     // Send back the response, do not restart the event loop
-    err = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 1 + 64 + 2);
+    err = io_seproxyhal_send_status(APDU_RESPONSE_OK, 65, false, false);
     if (G_called_from_swap) {
         PRINTF("G_called_from_swap\n");
 
@@ -65,61 +61,41 @@ unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_elemen
             finalize_exchange_sign_transaction(true);
         } else {
             PRINTF("Unrecoverable\n");
-            os_sched_exit(-1);
+            app_exit();
         }
     }
     reset_app_context();
-    // Display back the original UX
-    ui_idle();
     return 0;  // do not redraw the widget
 }
 
-unsigned int io_seproxyhal_touch_tx_cancel(__attribute__((unused)) const bagl_element_t *e) {
-    reset_app_context();
-    G_io_apdu_buffer[0] = 0x69;
-    G_io_apdu_buffer[1] = 0x85;
-    // Send back the response, do not restart the event loop
-    io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+unsigned int io_seproxyhal_touch_tx_cancel(void) {
+    return io_seproxyhal_send_status(APDU_RESPONSE_CONDITION_NOT_SATISFIED, 0, true, false);
 }
 
-unsigned int io_seproxyhal_touch_data_ok(__attribute__((unused)) const bagl_element_t *e) {
+unsigned int io_seproxyhal_touch_data_ok(void) {
     parserStatus_e txResult = USTREAM_FINISHED;
     txResult = continueTx(&txContext);
+    unsigned int err = 0;
     switch (txResult) {
         case USTREAM_SUSPENDED:
             break;
         case USTREAM_FINISHED:
+            err = finalizeParsing();
             break;
         case USTREAM_PROCESSING:
-            io_seproxyhal_send_status(0x9000);
-            ui_idle();
+            err = io_seproxyhal_send_status(APDU_RESPONSE_OK, 0, false, true);
             break;
         case USTREAM_FAULT:
-            reset_app_context();
-            io_seproxyhal_send_status(0x6A80);
-            ui_idle();
+            err = io_seproxyhal_send_status(APDU_RESPONSE_INVALID_DATA, 0, true, true);
             break;
         default:
             PRINTF("Unexpected parser status\n");
-            reset_app_context();
-            io_seproxyhal_send_status(0x6A80);
-            ui_idle();
+            err = io_seproxyhal_send_status(APDU_RESPONSE_INVALID_DATA, 0, true, true);
     }
 
-    if (txResult == USTREAM_FINISHED) {
-        finalizeParsing();
-    }
-
-    return 0;
+    return err;
 }
 
-unsigned int io_seproxyhal_touch_data_cancel(__attribute__((unused)) const bagl_element_t *e) {
-    reset_app_context();
-    io_seproxyhal_send_status(0x6985);
-    // Display back the original UX
-    ui_idle();
-    return 0;  // do not redraw the widget
+unsigned int io_seproxyhal_touch_data_cancel(void) {
+    return io_seproxyhal_send_status(APDU_RESPONSE_CONDITION_NOT_SATISFIED, 0, true, true);
 }
diff --git a/src_nbgl/ui_approve_tx.c b/src_nbgl/ui_approve_tx.c
index 13aea2264..e42209a57 100644
--- a/src_nbgl/ui_approve_tx.c
+++ b/src_nbgl/ui_approve_tx.c
@@ -5,7 +5,7 @@
 #include "ui_nbgl.h"
 #include "ui_signing.h"
 #include "plugins.h"
-#include "domain_name.h"
+#include "trusted_name.h"
 #include "caller_api.h"
 #include "network_icons.h"
 #include "network.h"
@@ -26,28 +26,22 @@ static char msg_buffer[MAX_PLUGIN_ITEMS][VALUE_MAX_LEN];
 struct tx_approval_context_t {
     bool fromPlugin;
     bool displayNetwork;
-#ifdef HAVE_DOMAIN_NAME
-    bool domain_name_match;
+#ifdef HAVE_TRUSTED_NAME
+    bool trusted_name_match;
 #endif
 };
 
 static struct tx_approval_context_t tx_approval_context;
 
-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 reviewChoice(bool confirm) {
     if (confirm) {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_SIGNED, confirmTransation);
+        io_seproxyhal_touch_tx_ok();
+        memset(&tx_approval_context, 0, sizeof(tx_approval_context));
+        nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_SIGNED, ui_idle);
     } else {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, reviewReject);
+        io_seproxyhal_touch_tx_cancel();
+        memset(&tx_approval_context, 0, sizeof(tx_approval_context));
+        nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle);
     }
 }
 
@@ -136,21 +130,22 @@ static uint8_t setTagValuePairs(void) {
         pairs[nbPairs].value = strings.common.fullAmount;
         nbPairs++;
 
-#ifdef HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_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) {
+        e_name_type type = TYPE_ACCOUNT;
+        tx_approval_context.trusted_name_match =
+            has_trusted_name(1, &type, &chain_id, tmpContent.txContent.destination);
+        if (tx_approval_context.trusted_name_match) {
             pairs[nbPairs].item = "To (domain)";
-            pairs[nbPairs].value = g_domain_name;
+            pairs[nbPairs].value = g_trusted_name;
             nbPairs++;
         }
-        if (!tx_approval_context.domain_name_match || N_storage.verbose_domain_name) {
+        if (!tx_approval_context.trusted_name_match || N_storage.verbose_trusted_name) {
 #endif
             pairs[nbPairs].item = "To";
             pairs[nbPairs].value = strings.common.toAddress;
             nbPairs++;
-#ifdef HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
         }
 #endif
         if (N_storage.displayNonce) {
@@ -172,20 +167,23 @@ static uint8_t setTagValuePairs(void) {
     return nbPairs;
 }
 
-static void reviewCommon(void) {
+void ux_approve_tx(bool fromPlugin) {
     explicit_bzero(&pairsList, sizeof(pairsList));
+    explicit_bzero(&tx_approval_context, sizeof(tx_approval_context));
+    tx_approval_context.fromPlugin = fromPlugin;
+
+    uint64_t chain_id = get_tx_chain_id();
+    if (chainConfig->chainId == ETHEREUM_MAINNET_CHAINID && chain_id != chainConfig->chainId) {
+        tx_approval_context.displayNetwork = true;
+    } else {
+        tx_approval_context.displayNetwork = false;
+    }
 
     pairsList.nbPairs = setTagValuePairs();
     pairsList.pairs = pairs;
-    nbgl_operationType_t op = TYPE_TRANSACTION;
 
-#if API_LEVEL >= 19
-    if (tmpContent.txContent.dataPresent) {
-        op |= BLIND_OPERATION;
-    }
-#endif
+    uint32_t buf_size = SHARED_BUFFER_SIZE / 2;
     if (tx_approval_context.fromPlugin) {
-        uint32_t buf_size = SHARED_BUFFER_SIZE / 2;
         char op_name[sizeof(strings.common.fullAmount)];
         plugin_ui_get_id();
 
@@ -203,36 +201,30 @@ static void reviewCommon(void) {
                  op_name,
                  (pluginType == EXTERNAL ? "on " : ""),
                  strings.common.toAddress);
+    } else {
+        snprintf(g_stax_shared_buffer, buf_size, REVIEW("transaction"));
+        snprintf(
+            g_stax_shared_buffer + buf_size,
+            buf_size,
+            tmpContent.txContent.dataPresent ? BLIND_SIGN("transaction") : SIGN("transaction"));
+    }
 
-        nbgl_useCaseReview(op,
+    if (tmpContent.txContent.dataPresent) {
+        nbgl_useCaseReviewBlindSigning(TYPE_TRANSACTION,
+                                       &pairsList,
+                                       get_tx_icon(),
+                                       g_stax_shared_buffer,
+                                       NULL,
+                                       g_stax_shared_buffer + buf_size,
+                                       NULL,
+                                       reviewChoice);
+    } else {
+        nbgl_useCaseReview(TYPE_TRANSACTION,
                            &pairsList,
                            get_tx_icon(),
                            g_stax_shared_buffer,
                            NULL,
                            g_stax_shared_buffer + buf_size,
                            reviewChoice);
-    } else {
-        nbgl_useCaseReview(
-            op,
-            &pairsList,
-            get_tx_icon(),
-            REVIEW("transaction"),
-            NULL,
-            tmpContent.txContent.dataPresent ? BLIND_SIGN("transaction") : SIGN("transaction"),
-            reviewChoice);
     }
 }
-
-void ux_approve_tx(bool fromPlugin) {
-    memset(&tx_approval_context, 0, sizeof(tx_approval_context));
-
-    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;
-    }
-
-    reviewCommon();
-}
diff --git a/src_nbgl/ui_blind_signing.c b/src_nbgl/ui_blind_signing.c
index 14bcbe7f0..ba0a40fb8 100644
--- a/src_nbgl/ui_blind_signing.c
+++ b/src_nbgl/ui_blind_signing.c
@@ -4,6 +4,7 @@
 #include "feature_signTx.h"
 #include "ui_nbgl.h"
 #include "apdu_constants.h"
+#include "context_712.h"
 
 static void ui_error_blind_signing_choice(bool confirm) {
     if (confirm) {
@@ -13,16 +14,6 @@ static void ui_error_blind_signing_choice(bool confirm) {
     }
 }
 
-static void ui_warning_blind_signing_choice(bool confirm) {
-    if (confirm) {
-        reset_app_context();
-        io_seproxyhal_send_status(APDU_RESPONSE_CONDITION_NOT_SATISFIED);
-        ui_idle();
-    } else {
-        start_signature_flow();
-    }
-}
-
 void ui_error_blind_signing(void) {
     nbgl_useCaseChoice(&C_Warning_64px,
                        "This transaction cannot be clear-signed",
@@ -31,13 +22,3 @@ void ui_error_blind_signing(void) {
                        "Reject transaction",
                        ui_error_blind_signing_choice);
 }
-
-void ui_warning_blind_signing(void) {
-    nbgl_useCaseChoice(&C_Warning_64px,
-                       "Blind signing ahead",
-                       "This transaction's details are not fully verifiable. If you sign it, you "
-                       "could lose all your assets.",
-                       "Back to safety",
-                       "Continue anyway",
-                       ui_warning_blind_signing_choice);
-}
diff --git a/src_nbgl/ui_confirm_parameter_selector.c b/src_nbgl/ui_confirm_parameter_selector.c
index e4dca607b..2292e6226 100644
--- a/src_nbgl/ui_confirm_parameter_selector.c
+++ b/src_nbgl/ui_confirm_parameter_selector.c
@@ -9,9 +9,9 @@ static nbgl_contentTagValueList_t pairsList;
 
 static void reviewChoice(bool confirm) {
     if (confirm) {
-        io_seproxyhal_touch_data_ok(NULL);
+        io_seproxyhal_touch_data_ok();
     } else {
-        io_seproxyhal_touch_data_cancel(NULL);
+        io_seproxyhal_touch_data_cancel();
     }
 }
 
diff --git a/src_nbgl/ui_display_privacy.c b/src_nbgl/ui_display_privacy.c
index 65b536337..209e0d99b 100644
--- a/src_nbgl/ui_display_privacy.c
+++ b/src_nbgl/ui_display_privacy.c
@@ -6,9 +6,9 @@
 
 static void reviewChoice(bool confirm) {
     if (confirm) {
-        io_seproxyhal_touch_privacy_ok(NULL);
+        io_seproxyhal_touch_privacy_ok();
     } else {
-        io_seproxyhal_touch_privacy_cancel(NULL);
+        io_seproxyhal_touch_privacy_cancel();
     }
 }
 
diff --git a/src_nbgl/ui_get_eth2_public_key.c b/src_nbgl/ui_get_eth2_public_key.c
index 99d09a56b..e9b2ded0f 100644
--- a/src_nbgl/ui_get_eth2_public_key.c
+++ b/src_nbgl/ui_get_eth2_public_key.c
@@ -4,19 +4,13 @@
 #include "ui_nbgl.h"
 #include "uint_common.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) {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, confirmTransation);
+        io_seproxyhal_touch_address_ok();
+        nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_idle);
     } else {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, reviewReject);
+        io_seproxyhal_touch_address_cancel();
+        nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_idle);
     }
 }
 
diff --git a/src_nbgl/ui_get_public_key.c b/src_nbgl/ui_get_public_key.c
index bc00ab690..bcaccfb78 100644
--- a/src_nbgl/ui_get_public_key.c
+++ b/src_nbgl/ui_get_public_key.c
@@ -1,23 +1,17 @@
-#include <nbgl_page.h>
+#include "nbgl_use_case.h"
 #include "shared_context.h"
 #include "ui_callbacks.h"
 #include "ui_nbgl.h"
 #include "network.h"
 #include "network_icons.h"
 
-static void cancel_send(void) {
-    io_seproxyhal_touch_address_cancel(NULL);
-}
-
-static void confirm_send(void) {
-    io_seproxyhal_touch_address_ok(NULL);
-}
-
 static void review_choice(bool confirm) {
     if (confirm) {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, confirm_send);
+        io_seproxyhal_touch_address_ok();
+        nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_idle);
     } else {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, cancel_send);
+        io_seproxyhal_touch_address_cancel();
+        nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_idle);
     }
 }
 
diff --git a/src_nbgl/ui_home.c b/src_nbgl/ui_home.c
index 8c3accbc8..9eaf38fb9 100644
--- a/src_nbgl/ui_home.c
+++ b/src_nbgl/ui_home.c
@@ -15,8 +15,8 @@
 
 enum {
     BLIND_SIGNING_TOKEN = FIRST_USER_TOKEN,
-#ifdef HAVE_DOMAIN_NAME
-    DOMAIN_NAME_VERBOSE_TOKEN,
+#ifdef HAVE_TRUSTED_NAME
+    TRUSTED_NAME_VERBOSE_TOKEN,
 #endif
     NONCE_TOKEN,
 #ifdef HAVE_EIP712_FULL_SUPPORT
@@ -27,8 +27,8 @@ enum {
 
 enum {
     BLIND_SIGNING_ID,
-#ifdef HAVE_DOMAIN_NAME
-    DOMAIN_NAME_VERBOSE_ID,
+#ifdef HAVE_TRUSTED_NAME
+    TRUSTED_NAME_VERBOSE_ID,
 #endif
     NONCE_ID,
 #ifdef HAVE_EIP712_FULL_SUPPORT
@@ -61,13 +61,13 @@ static void setting_toggle_callback(int token, uint8_t index, int page) {
             switches[BLIND_SIGNING_ID].initState = (nbgl_state_t) value;
             nvm_write((void *) &N_storage.dataAllowed, (void *) &value, sizeof(value));
             break;
-#ifdef HAVE_DOMAIN_NAME
-        case DOMAIN_NAME_VERBOSE_TOKEN:
-            value = !N_storage.verbose_domain_name;
-            switches[DOMAIN_NAME_VERBOSE_ID].initState = (nbgl_state_t) value;
-            nvm_write((void *) &N_storage.verbose_domain_name, (void *) &value, sizeof(value));
+#ifdef HAVE_TRUSTED_NAME
+        case TRUSTED_NAME_VERBOSE_TOKEN:
+            value = !N_storage.verbose_trusted_name;
+            switches[TRUSTED_NAME_VERBOSE_ID].initState = (nbgl_state_t) value;
+            nvm_write((void *) &N_storage.verbose_trusted_name, (void *) &value, sizeof(value));
             break;
-#endif  // HAVE_DOMAIN_NAME
+#endif  // HAVE_TRUSTED_NAME
         case NONCE_TOKEN:
             value = !N_storage.displayNonce;
             switches[NONCE_ID].initState = (nbgl_state_t) value;
@@ -90,7 +90,7 @@ static void setting_toggle_callback(int token, uint8_t index, int page) {
 
 static void app_quit(void) {
     // exit app here
-    os_sched_exit(-1);
+    app_exit();
 }
 
 const nbgl_icon_details_t *get_app_icon(bool caller_icon) {
@@ -123,14 +123,14 @@ static void prepare_and_display_home(const char *appname, const char *tagline, u
     switches[BLIND_SIGNING_ID].token = BLIND_SIGNING_TOKEN;
     switches[BLIND_SIGNING_ID].tuneId = TUNE_TAP_CASUAL;
 
-#ifdef HAVE_DOMAIN_NAME
-    switches[DOMAIN_NAME_VERBOSE_ID].initState =
-        N_storage.verbose_domain_name ? ON_STATE : OFF_STATE;
-    switches[DOMAIN_NAME_VERBOSE_ID].text = "ENS addresses";
-    switches[DOMAIN_NAME_VERBOSE_ID].subText = "Display the resolved address of ENS domains.";
-    switches[DOMAIN_NAME_VERBOSE_ID].token = DOMAIN_NAME_VERBOSE_TOKEN;
-    switches[DOMAIN_NAME_VERBOSE_ID].tuneId = TUNE_TAP_CASUAL;
-#endif  // HAVE_DOMAIN_NAME
+#ifdef HAVE_TRUSTED_NAME
+    switches[TRUSTED_NAME_VERBOSE_ID].initState =
+        N_storage.verbose_trusted_name ? ON_STATE : OFF_STATE;
+    switches[TRUSTED_NAME_VERBOSE_ID].text = "ENS addresses";
+    switches[TRUSTED_NAME_VERBOSE_ID].subText = "Display the resolved address of ENS domains.";
+    switches[TRUSTED_NAME_VERBOSE_ID].token = TRUSTED_NAME_VERBOSE_TOKEN;
+    switches[TRUSTED_NAME_VERBOSE_ID].tuneId = TUNE_TAP_CASUAL;
+#endif  // HAVE_TRUSTED_NAME
 
     switches[NONCE_ID].initState = N_storage.displayNonce ? ON_STATE : OFF_STATE;
     switches[NONCE_ID].text = "Nonce";
diff --git a/src_nbgl/ui_message_signing.c b/src_nbgl/ui_message_signing.c
index 4fd171a19..ff18abb9f 100644
--- a/src_nbgl/ui_message_signing.c
+++ b/src_nbgl/ui_message_signing.c
@@ -1,18 +1,12 @@
 #include "ui_nbgl.h"
 #include "ui_logic.h"
 
-static void ui_message_712_approved(void) {
-    ui_712_approve();
-}
-
-static void ui_message_712_rejected(void) {
-    ui_712_reject();
-}
-
 void ui_typed_message_review_choice(bool confirm) {
     if (confirm) {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, ui_message_712_approved);
+        ui_712_approve();
+        nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, ui_idle);
     } else {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, ui_message_712_rejected);
+        ui_712_reject();
+        nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, ui_idle);
     }
 }
diff --git a/src_nbgl/ui_message_signing.h b/src_nbgl/ui_message_signing.h
index 48412fe41..cbdb7b22c 100644
--- a/src_nbgl/ui_message_signing.h
+++ b/src_nbgl/ui_message_signing.h
@@ -4,10 +4,11 @@
 #include <stdbool.h>
 #include "ui_signing.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)
+#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)
+#define TEXT_BLIND_SIGN_EIP712 BLIND_SIGN(TEXT_TYPED_MESSAGE)
 
 void ui_typed_message_review_choice(bool confirm);
 
diff --git a/src_nbgl/ui_sign_712.c b/src_nbgl/ui_sign_712.c
index 10b27d35d..cd4afcf90 100644
--- a/src_nbgl/ui_sign_712.c
+++ b/src_nbgl/ui_sign_712.c
@@ -8,26 +8,31 @@
 #include "nbgl_use_case.h"
 #include "ui_message_signing.h"
 #include "ledger_assert.h"
+#include "apdu_constants.h"
 
-static nbgl_contentTagValue_t pairs[6];
+static nbgl_contentTagValue_t pairs[7];
 static nbgl_contentTagValueList_t pairs_list;
 static uint8_t pair_idx;
 static size_t buf_idx;
+static bool filtered;
+static bool review_skipped;
 
 static void message_progress(bool confirm) {
     char *buf;
     size_t buf_size;
     size_t shift_off;
 
-    if (pairs_list.nbPairs < pair_idx) {
-        buf = get_ui_pairs_buffer(&buf_size);
-        memmove(&pairs[0], &pairs[pairs_list.nbPairs], sizeof(pairs[0]));
-        memmove(buf, pairs[0].item, (buf + buf_idx) - pairs[0].item);
-        shift_off = pairs[0].item - buf;
-        buf_idx -= shift_off;
-        pairs[0].value -= shift_off;
-        pairs[0].item = buf;
-        pair_idx = 1;
+    if (!review_skipped) {
+        if (pairs_list.nbPairs < pair_idx) {
+            buf = get_ui_pairs_buffer(&buf_size);
+            memmove(&pairs[0], &pairs[pairs_list.nbPairs], sizeof(pairs[0]));
+            memmove(buf, pairs[0].item, (buf + buf_idx) - pairs[0].item);
+            shift_off = pairs[0].item - buf;
+            buf_idx -= shift_off;
+            pairs[0].value -= shift_off;
+            pairs[0].item = buf;
+            pair_idx = 1;
+        }
     }
     if (confirm) {
         if (ui_712_next_field() == EIP712_NO_MORE_FIELD) {
@@ -38,6 +43,11 @@ static void message_progress(bool confirm) {
     }
 }
 
+static void review_skip(void) {
+    review_skipped = true;
+    message_progress(true);
+}
+
 static void message_update(bool confirm) {
     char *buf;
     size_t buf_size;
@@ -46,18 +56,21 @@ static void message_update(bool confirm) {
 
     buf = get_ui_pairs_buffer(&buf_size);
     if (confirm) {
-        buf_off = strlen(strings.tmp.tmp2) + 1;
-        LEDGER_ASSERT((buf_idx + buf_off) < buf_size, "UI pairs buffer overflow");
-        pairs[pair_idx].item = memmove(buf + buf_idx, strings.tmp.tmp2, buf_off);
-        buf_idx += buf_off;
-        buf_off = strlen(strings.tmp.tmp) + 1;
-        LEDGER_ASSERT((buf_idx + buf_off) < buf_size, "UI pairs buffer overflow");
-        pairs[pair_idx].value = memmove(buf + buf_idx, strings.tmp.tmp, buf_off);
-        buf_idx += buf_off;
-        pair_idx += 1;
-        pairs_list.nbPairs = nbgl_useCaseGetNbTagValuesInPage(pair_idx, &pairs_list, 0, &flag);
-        if (pairs_list.nbPairs < pair_idx) {
-            nbgl_useCaseReviewStreamingContinue(&pairs_list, message_progress);
+        if (!review_skipped) {
+            buf_off = strlen(strings.tmp.tmp2) + 1;
+            LEDGER_ASSERT((buf_idx + buf_off) < buf_size, "UI pairs buffer overflow");
+            pairs[pair_idx].item = memmove(buf + buf_idx, strings.tmp.tmp2, buf_off);
+            buf_idx += buf_off;
+            buf_off = strlen(strings.tmp.tmp) + 1;
+            LEDGER_ASSERT((buf_idx + buf_off) < buf_size, "UI pairs buffer overflow");
+            pairs[pair_idx].value = memmove(buf + buf_idx, strings.tmp.tmp, buf_off);
+            buf_idx += buf_off;
+            pair_idx += 1;
+            pairs_list.nbPairs =
+                nbgl_useCaseGetNbTagValuesInPageExt(pair_idx, &pairs_list, 0, !filtered, &flag);
+        }
+        if (!review_skipped && ((pair_idx == ARRAYLEN(pairs)) || (pairs_list.nbPairs < pair_idx))) {
+            nbgl_useCaseReviewStreamingContinueExt(&pairs_list, message_progress, review_skip);
         } else {
             message_progress(true);
         }
@@ -66,13 +79,27 @@ static void message_update(bool confirm) {
     }
 }
 
-void ui_712_start(void) {
+static void ui_712_start_common(bool has_filtering) {
     explicit_bzero(&pairs, sizeof(pairs));
     explicit_bzero(&pairs_list, sizeof(pairs_list));
     pairs_list.pairs = pairs;
     pair_idx = 0;
     buf_idx = 0;
+    filtered = has_filtering;
+    review_skipped = false;
+}
 
+void ui_712_start_unfiltered(void) {
+    ui_712_start_common(false);
+    nbgl_useCaseReviewStreamingBlindSigningStart(TYPE_MESSAGE | SKIPPABLE_OPERATION,
+                                                 &C_Review_64px,
+                                                 TEXT_REVIEW_EIP712,
+                                                 NULL,
+                                                 message_update);
+}
+
+void ui_712_start(void) {
+    ui_712_start_common(true);
     nbgl_useCaseReviewStreamingStart(TYPE_MESSAGE,
                                      &C_Review_64px,
                                      TEXT_REVIEW_EIP712,
@@ -85,12 +112,13 @@ void ui_712_switch_to_message(void) {
 }
 
 void ui_712_switch_to_sign(void) {
-    if (pair_idx > 0) {
+    if (!review_skipped && (pair_idx > 0)) {
         pairs_list.nbPairs = pair_idx;
         pair_idx = 0;
-        nbgl_useCaseReviewStreamingContinue(&pairs_list, message_progress);
+        nbgl_useCaseReviewStreamingContinueExt(&pairs_list, message_progress, review_skip);
     } else {
-        nbgl_useCaseReviewStreamingFinish(TEXT_SIGN_EIP712, ui_typed_message_review_choice);
+        nbgl_useCaseReviewStreamingFinish(filtered ? TEXT_SIGN_EIP712 : TEXT_BLIND_SIGN_EIP712,
+                                          ui_typed_message_review_choice);
     }
 }
 
diff --git a/src_nbgl/ui_sign_712_v0.c b/src_nbgl/ui_sign_712_v0.c
index a3a39b7d2..4b8489e51 100644
--- a/src_nbgl/ui_sign_712_v0.c
+++ b/src_nbgl/ui_sign_712_v0.c
@@ -32,11 +32,12 @@ void ui_sign_712_v0(void) {
     pairs_list.pairs = pairs;
     pairs_list.nbMaxLinesForValue = 0;
 
-    nbgl_useCaseReview(TYPE_MESSAGE,
-                       &pairs_list,
-                       &C_Review_64px,
-                       TEXT_REVIEW_EIP712,
-                       NULL,
-                       TEXT_SIGN_EIP712,
-                       ui_typed_message_review_choice);
+    nbgl_useCaseReviewBlindSigning(TYPE_TRANSACTION,
+                                   &pairs_list,
+                                   &C_Review_64px,
+                                   TEXT_REVIEW_EIP712,
+                                   NULL,
+                                   TEXT_BLIND_SIGN_EIP712,
+                                   NULL,
+                                   ui_typed_message_review_choice);
 }
diff --git a/src_nbgl/ui_sign_message.c b/src_nbgl/ui_sign_message.c
index 93312a064..efabd82d2 100644
--- a/src_nbgl/ui_sign_message.c
+++ b/src_nbgl/ui_sign_message.c
@@ -29,19 +29,13 @@ static bool g_skipped;
 
 static void ui_191_process_state(void);
 
-static void reject_message(void) {
-    io_seproxyhal_touch_signMessage_cancel();
-}
-
-static void sign_message(void) {
-    io_seproxyhal_touch_signMessage_ok();
-}
-
 static void ui_191_finish_cb(bool confirm) {
     if (confirm) {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, sign_message);
+        io_seproxyhal_touch_signMessage_ok();
+        nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, ui_idle);
     } else {
-        nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, reject_message);
+        io_seproxyhal_touch_signMessage_cancel();
+        nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, ui_idle);
     }
 }
 
diff --git a/src_plugins/erc1155/erc1155_plugin.c b/src_plugins/erc1155/erc1155_plugin.c
index b1704ca2a..24ca169b2 100644
--- a/src_plugins/erc1155/erc1155_plugin.c
+++ b/src_plugins/erc1155/erc1155_plugin.c
@@ -16,8 +16,7 @@ const uint8_t *const ERC1155_SELECTORS[SELECTORS_COUNT] = {
     ERC1155_SAFE_BATCH_TRANSFER,
 };
 
-static void handle_init_contract(void *parameters) {
-    ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
+void handle_init_contract_1155(ethPluginInitContract_t *msg) {
     erc1155_context_t *context = (erc1155_context_t *) msg->pluginContext;
 
     if (NO_NFT_METADATA) {
@@ -56,8 +55,7 @@ static void handle_init_contract(void *parameters) {
     }
 }
 
-static void handle_finalize(void *parameters) {
-    ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
+void handle_finalize_1155(ethPluginFinalize_t *msg) {
     erc1155_context_t *context = (erc1155_context_t *) msg->pluginContext;
 
     if (context->selectorIndex != SAFE_BATCH_TRANSFER) {
@@ -92,14 +90,11 @@ static void handle_finalize(void *parameters) {
     msg->result = ETH_PLUGIN_RESULT_OK;
 }
 
-static void handle_provide_info(void *parameters) {
-    ethPluginProvideInfo_t *msg = (ethPluginProvideInfo_t *) parameters;
-
+void handle_provide_info_1155(ethPluginProvideInfo_t *msg) {
     msg->result = ETH_PLUGIN_RESULT_OK;
 }
 
-static void handle_query_contract_id(void *parameters) {
-    ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
+void handle_query_contract_id_1155(ethQueryContractID_t *msg) {
     erc1155_context_t *context = (erc1155_context_t *) msg->pluginContext;
 
     msg->result = ETH_PLUGIN_RESULT_OK;
@@ -131,22 +126,22 @@ static void handle_query_contract_id(void *parameters) {
 void erc1155_plugin_call(int message, void *parameters) {
     switch (message) {
         case ETH_PLUGIN_INIT_CONTRACT: {
-            handle_init_contract(parameters);
+            handle_init_contract_1155((ethPluginInitContract_t *) parameters);
         } break;
         case ETH_PLUGIN_PROVIDE_PARAMETER: {
-            handle_provide_parameter_1155(parameters);
+            handle_provide_parameter_1155((ethPluginProvideParameter_t *) parameters);
         } break;
         case ETH_PLUGIN_FINALIZE: {
-            handle_finalize(parameters);
+            handle_finalize_1155((ethPluginFinalize_t *) parameters);
         } break;
         case ETH_PLUGIN_PROVIDE_INFO: {
-            handle_provide_info(parameters);
+            handle_provide_info_1155((ethPluginProvideInfo_t *) parameters);
         } break;
         case ETH_PLUGIN_QUERY_CONTRACT_ID: {
-            handle_query_contract_id(parameters);
+            handle_query_contract_id_1155((ethQueryContractID_t *) parameters);
         } break;
         case ETH_PLUGIN_QUERY_CONTRACT_UI: {
-            handle_query_contract_ui_1155(parameters);
+            handle_query_contract_ui_1155((ethQueryContractUI_t *) parameters);
         } break;
         default:
             PRINTF("Unhandled message %d\n", message);
diff --git a/src_plugins/erc1155/erc1155_plugin.h b/src_plugins/erc1155/erc1155_plugin.h
index a60dab69b..d9615dfeb 100644
--- a/src_plugins/erc1155/erc1155_plugin.h
+++ b/src_plugins/erc1155/erc1155_plugin.h
@@ -8,6 +8,7 @@
 #include "ethUstream.h"
 #include "uint256.h"
 #include "asset_info.h"
+#include "eth_plugin_interface.h"
 
 // Internal plugin for EIP 1155: https://eips.ethereum.org/EIPS/eip-1155
 
@@ -48,8 +49,8 @@ typedef struct erc1155_context_t {
     uint8_t selectorIndex;
 } erc1155_context_t;
 
-void handle_provide_parameter_1155(void *parameters);
-void handle_query_contract_ui_1155(void *parameters);
+void handle_provide_parameter_1155(ethPluginProvideParameter_t *parameters);
+void handle_query_contract_ui_1155(ethQueryContractUI_t *parameters);
 
 #endif  // HAVE_NFT_SUPPORT
 
diff --git a/src_plugins/erc1155/erc1155_provide_parameters.c b/src_plugins/erc1155/erc1155_provide_parameters.c
index 454f9a233..3a9f7bb88 100644
--- a/src_plugins/erc1155/erc1155_provide_parameters.c
+++ b/src_plugins/erc1155/erc1155_provide_parameters.c
@@ -115,8 +115,7 @@ static void handle_approval_for_all(ethPluginProvideParameter_t *msg, erc1155_co
     }
 }
 
-void handle_provide_parameter_1155(void *parameters) {
-    ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
+void handle_provide_parameter_1155(ethPluginProvideParameter_t *msg) {
     erc1155_context_t *context = (erc1155_context_t *) msg->pluginContext;
 
     PRINTF("erc1155 plugin provide parameter %d %.*H\n",
diff --git a/src_plugins/erc1155/erc1155_ui.c b/src_plugins/erc1155/erc1155_ui.c
index 1e9d45136..f566ad5f7 100644
--- a/src_plugins/erc1155/erc1155_ui.c
+++ b/src_plugins/erc1155/erc1155_ui.c
@@ -132,8 +132,7 @@ static void set_batch_transfer_ui(ethQueryContractUI_t *msg, erc1155_context_t *
     }
 }
 
-void handle_query_contract_ui_1155(void *parameters) {
-    ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
+void handle_query_contract_ui_1155(ethQueryContractUI_t *msg) {
     erc1155_context_t *context = (erc1155_context_t *) msg->pluginContext;
 
     msg->result = ETH_PLUGIN_RESULT_OK;
diff --git a/src_plugins/erc20/erc20_plugin.c b/src_plugins/erc20/erc20_plugin.c
index 009336f61..2dd28f8d1 100644
--- a/src_plugins/erc20/erc20_plugin.c
+++ b/src_plugins/erc20/erc20_plugin.c
@@ -190,7 +190,8 @@ void erc20_plugin_call(int message, void *parameters) {
                                             context->ticker,
                                             msg->msg,
                                             100)) {
-                            THROW(EXCEPTION_OVERFLOW);
+                            msg->result = ETH_PLUGIN_RESULT_ERROR;
+                            break;
                         }
                     }
                     msg->result = ETH_PLUGIN_RESULT_OK;
diff --git a/src_plugins/erc721/erc721_plugin.c b/src_plugins/erc721/erc721_plugin.c
index 07ba0c7a6..10fb28cec 100644
--- a/src_plugins/erc721/erc721_plugin.c
+++ b/src_plugins/erc721/erc721_plugin.c
@@ -21,8 +21,7 @@ const uint8_t *const ERC721_SELECTORS[SELECTORS_COUNT] = {
     ERC721_SAFE_TRANSFER_DATA_SELECTOR,
 };
 
-static void handle_init_contract(void *parameters) {
-    ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
+void handle_init_contract_721(ethPluginInitContract_t *msg) {
     erc721_context_t *context = (erc721_context_t *) msg->pluginContext;
 
     if (NO_NFT_METADATA) {
@@ -63,8 +62,7 @@ static void handle_init_contract(void *parameters) {
     }
 }
 
-static void handle_finalize(void *parameters) {
-    ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
+void handle_finalize_721(ethPluginFinalize_t *msg) {
     erc721_context_t *context = (erc721_context_t *) msg->pluginContext;
 
     msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
@@ -99,14 +97,11 @@ static void handle_finalize(void *parameters) {
     msg->result = ETH_PLUGIN_RESULT_OK;
 }
 
-static void handle_provide_info(void *parameters) {
-    ethPluginProvideInfo_t *msg = (ethPluginProvideInfo_t *) parameters;
-
+void handle_provide_info_721(ethPluginProvideInfo_t *msg) {
     msg->result = ETH_PLUGIN_RESULT_OK;
 }
 
-static void handle_query_contract_id(void *parameters) {
-    ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
+void handle_query_contract_id_721(ethQueryContractID_t *msg) {
     erc721_context_t *context = (erc721_context_t *) msg->pluginContext;
 
     msg->result = ETH_PLUGIN_RESULT_OK;
@@ -138,22 +133,22 @@ static void handle_query_contract_id(void *parameters) {
 void erc721_plugin_call(int message, void *parameters) {
     switch (message) {
         case ETH_PLUGIN_INIT_CONTRACT: {
-            handle_init_contract(parameters);
+            handle_init_contract_721((ethPluginInitContract_t *) parameters);
         } break;
         case ETH_PLUGIN_PROVIDE_PARAMETER: {
-            handle_provide_parameter_721(parameters);
+            handle_provide_parameter_721((ethPluginProvideParameter_t *) parameters);
         } break;
         case ETH_PLUGIN_FINALIZE: {
-            handle_finalize(parameters);
+            handle_finalize_721((ethPluginFinalize_t *) parameters);
         } break;
         case ETH_PLUGIN_PROVIDE_INFO: {
-            handle_provide_info(parameters);
+            handle_provide_info_721((ethPluginProvideInfo_t *) parameters);
         } break;
         case ETH_PLUGIN_QUERY_CONTRACT_ID: {
-            handle_query_contract_id(parameters);
+            handle_query_contract_id_721((ethQueryContractID_t *) parameters);
         } break;
         case ETH_PLUGIN_QUERY_CONTRACT_UI: {
-            handle_query_contract_ui_721(parameters);
+            handle_query_contract_ui_721((ethQueryContractUI_t *) parameters);
         } break;
         default:
             PRINTF("Unhandled message %d\n", message);
diff --git a/src_plugins/erc721/erc721_plugin.h b/src_plugins/erc721/erc721_plugin.h
index 685c5e9d0..42f1df68e 100644
--- a/src_plugins/erc721/erc721_plugin.h
+++ b/src_plugins/erc721/erc721_plugin.h
@@ -7,6 +7,7 @@
 #include <stdint.h>
 #include "ethUstream.h"
 #include "asset_info.h"
+#include "eth_plugin_interface.h"
 
 // Internal plugin for EIP 721: https://eips.ethereum.org/EIPS/eip-721
 
@@ -39,8 +40,8 @@ typedef struct erc721_context_t {
     uint8_t selectorIndex;
 } erc721_context_t;
 
-void handle_provide_parameter_721(void *parameters);
-void handle_query_contract_ui_721(void *parameters);
+void handle_provide_parameter_721(ethPluginProvideParameter_t *parameters);
+void handle_query_contract_ui_721(ethQueryContractUI_t *parameters);
 
 #endif  // HAVE_NFT_SUPPORT
 
diff --git a/src_plugins/erc721/erc721_provide_parameters.c b/src_plugins/erc721/erc721_provide_parameters.c
index 18a19cb6e..d5577db6d 100644
--- a/src_plugins/erc721/erc721_provide_parameters.c
+++ b/src_plugins/erc721/erc721_provide_parameters.c
@@ -63,8 +63,7 @@ static void handle_approval_for_all(ethPluginProvideParameter_t *msg, erc721_con
     }
 }
 
-void handle_provide_parameter_721(void *parameters) {
-    ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
+void handle_provide_parameter_721(ethPluginProvideParameter_t *msg) {
     erc721_context_t *context = (erc721_context_t *) msg->pluginContext;
 
     PRINTF("erc721 plugin provide parameter %d %.*H\n",
diff --git a/src_plugins/erc721/erc721_ui.c b/src_plugins/erc721/erc721_ui.c
index 1c0facd3d..d27643108 100644
--- a/src_plugins/erc721/erc721_ui.c
+++ b/src_plugins/erc721/erc721_ui.c
@@ -121,8 +121,7 @@ static void set_transfer_ui(ethQueryContractUI_t *msg, erc721_context_t *context
     }
 }
 
-void handle_query_contract_ui_721(void *parameters) {
-    ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
+void handle_query_contract_ui_721(ethQueryContractUI_t *msg) {
     erc721_context_t *context = (erc721_context_t *) msg->pluginContext;
 
     msg->result = ETH_PLUGIN_RESULT_OK;
diff --git a/src_plugins/eth2/eth2_plugin.c b/src_plugins/eth2/eth2_plugin.c
index 9c42e3134..7cc3269aa 100644
--- a/src_plugins/eth2/eth2_plugin.c
+++ b/src_plugins/eth2/eth2_plugin.c
@@ -207,7 +207,8 @@ void eth2_plugin_call(int message, void *parameters) {
                                         ticker,
                                         msg->msg,
                                         100)) {
-                        THROW(EXCEPTION_OVERFLOW);
+                        msg->result = ETH_PLUGIN_RESULT_ERROR;
+                        break;
                     }
                     msg->result = ETH_PLUGIN_RESULT_OK;
                 } break;
diff --git a/src_plugins/swap_with_calldata_plugin.c b/src_plugins/swap_with_calldata_plugin.c
new file mode 100644
index 000000000..b9ccf7d90
--- /dev/null
+++ b/src_plugins/swap_with_calldata_plugin.c
@@ -0,0 +1,137 @@
+#include <string.h>
+#include "lib_cxng/src/cx_sha256.h"
+#include "plugin_utils.h"
+#include "eth_plugin_internal.h"
+#include "eth_plugin_interface.h"
+#include "eth_plugin_handler.h"
+
+/* SWAP_WITH_CALLDATA 'internal plugin'
+ *
+ * This internal plugin is used to parse calldata in the SWAP_WITH_CALLDATA context.
+ * Used for example by Thorswap and LiFi.
+ * Difference with main swap mode:
+ * - The swap transaction promise made by the partner contains a 32 bytes hash additional field
+ * - This hash is the hash of the calldata of the final signing transaction
+ * - During the final TX signature in ETH, we check the destination and amount as usual
+ * - We also check the hash of the calldata against the promised hash.
+ *
+ * This minimalist internal plugin is used to do this calldata hashing and check.
+ */
+
+typedef struct swap_with_calldata_context_s {
+    // Hash of the calldata received.
+    // Computed on (Selector + N * 32bytes parameters)
+    // We don't care at all about the content, we'll just compare the hash with the promised hash.
+    cx_sha256_t update_hash;
+} swap_with_calldata_context_t;
+
+void handle_init_contract_swap_with_calldata(ethPluginInitContract_t *msg) {
+    PRINTF("handle_init_contract_swap_with_calldata\n");
+    if (!G_called_from_swap) {
+        // Can't happen in theory, but let's double check.
+        PRINTF("swap_with_calldata plugin can't be used outside of SWAP context");
+        msg->result = ETH_PLUGIN_RESULT_ERROR;
+        return;
+    }
+
+    swap_with_calldata_context_t *context = (swap_with_calldata_context_t *) msg->pluginContext;
+
+    PRINTF("swap_with_calldata plugin init contract %.*H\n", SELECTOR_SIZE, msg->selector);
+
+    // Can't fail
+    cx_sha256_init_no_throw(&context->update_hash);
+
+    if (cx_sha256_update(&context->update_hash, msg->selector, SELECTOR_SIZE) != CX_OK) {
+        PRINTF("ERROR: cx_sha256_update on selector\n");
+        msg->result = ETH_PLUGIN_RESULT_ERROR;
+    } else {
+        msg->result = ETH_PLUGIN_RESULT_OK;
+    }
+}
+
+void handle_provide_parameter_swap_with_calldata(ethPluginProvideParameter_t *msg) {
+    PRINTF("handle_provide_parameter_swap_with_calldata\n");
+    if (!G_called_from_swap) {
+        // Can't happen in theory, but let's double check.
+        PRINTF("swap_with_calldata plugin can't be used outside of SWAP context");
+        msg->result = ETH_PLUGIN_RESULT_ERROR;
+        return;
+    }
+
+    swap_with_calldata_context_t *context = (swap_with_calldata_context_t *) msg->pluginContext;
+
+    PRINTF("swap_with_calldata plugin provide parameter %d %.*H\n",
+           msg->parameterOffset,
+           PARAMETER_LENGTH,
+           msg->parameter);
+
+    if (cx_sha256_update(&context->update_hash, msg->parameter, PARAMETER_LENGTH) != CX_OK) {
+        PRINTF("ERROR: cx_sha256_update on parameter %d\n", msg->parameterOffset);
+        msg->result = ETH_PLUGIN_RESULT_ERROR;
+    } else {
+        msg->result = ETH_PLUGIN_RESULT_OK;
+    }
+}
+
+void handle_finalize_swap_with_calldata(ethPluginFinalize_t *msg) {
+    PRINTF("handle_finalize_swap_with_calldata\n");
+    if (!G_called_from_swap) {
+        // Can't happen in theory, but let's double check.
+        PRINTF("swap_with_calldata plugin can't be used outside of SWAP context");
+        msg->result = ETH_PLUGIN_RESULT_ERROR;
+        return;
+    }
+
+    swap_with_calldata_context_t *context = (swap_with_calldata_context_t *) msg->pluginContext;
+
+    // Can't fail
+    uint8_t hash_digest[CX_SHA256_SIZE];
+    cx_sha256_final(&context->update_hash, hash_digest);
+
+    // Compare computed hash with promise made in Exchange by the partner
+    if (memcmp(hash_digest, G_swap_crosschain_hash, CX_SHA256_SIZE) != 0) {
+        PRINTF("ERROR: Wrong hash, promised %.*H, received %.*H\n",
+               CX_SHA256_SIZE,
+               G_swap_crosschain_hash,
+               CX_SHA256_SIZE,
+               hash_digest);
+        G_swap_mode = SWAP_MODE_ERROR;
+    } else {
+        PRINTF("Finalize successful, hashes match\n");
+        if (G_swap_mode == SWAP_MODE_CROSSCHAIN_PENDING_CHECK) {
+            // Remember that a calldata exists and is valid
+            // This differentiates the case were there was no calldata is provided
+            G_swap_mode = SWAP_MODE_CROSSCHAIN_SUCCESS;
+        } else {
+            PRINTF("G_swap_mode %d wrong, refusing to validate the calldata", G_swap_mode);
+            G_swap_mode = SWAP_MODE_ERROR;
+        }
+    }
+
+    // We use fallback so that the Eth UI takes back the display
+    // This is simpler than forwarding the values in txContent
+    // We return this even in case of errors because the error handling is done with G_swap_mode
+    msg->result = ETH_PLUGIN_RESULT_FALLBACK;
+    msg->tokenLookup1 = NULL;
+    msg->tokenLookup2 = NULL;
+}
+
+void swap_with_calldata_plugin_call(int message, void *parameters) {
+    switch (message) {
+        case ETH_PLUGIN_INIT_CONTRACT:
+            handle_init_contract_swap_with_calldata((ethPluginInitContract_t *) parameters);
+            break;
+        case ETH_PLUGIN_PROVIDE_PARAMETER:
+            handle_provide_parameter_swap_with_calldata((ethPluginProvideParameter_t *) parameters);
+            break;
+        case ETH_PLUGIN_FINALIZE:
+            handle_finalize_swap_with_calldata((ethPluginFinalize_t *) parameters);
+            break;
+        case ETH_PLUGIN_PROVIDE_INFO:
+        case ETH_PLUGIN_QUERY_CONTRACT_ID:
+        case ETH_PLUGIN_QUERY_CONTRACT_UI:
+        default:
+            PRINTF("Unhandled message %d\n", message);
+            break;
+    }
+}
diff --git a/tools/copy_clones.sh b/tools/copy_clones.sh
index 6fcf062cd..71c7d043a 100755
--- a/tools/copy_clones.sh
+++ b/tools/copy_clones.sh
@@ -5,6 +5,7 @@ DEVICES=(nanos nanos2 nanox stax flex)
 for dev in "${DEVICES[@]}"; do
     elf_file="build/${dev}/bin/app.elf"
     if [[ -f ${elf_file} ]]; then
+        mkdir -p "tests/ragger/.test_dependencies/clone/build/${dev}/bin/"
         cp "${elf_file}" "tests/ragger/.test_dependencies/clone/build/${dev}/bin/"
     else
         echo "Ignoring unknown file/dev: ${elf_file}"


Test patch:
diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml
index 974ee5fb7..65ebfa0cd 100644
--- a/.github/workflows/build_and_functional_tests.yml
+++ b/.github/workflows/build_and_functional_tests.yml
@@ -10,6 +10,15 @@ name: Build and run functional tests using ragger through reusable workflow
 
 on:
   workflow_dispatch:
+    inputs:
+      golden_run:
+        type: choice
+        required: true
+        default: 'Raise an error (default)'
+        description: CI behavior if the test snaphots are different than expected.
+        options:
+          - 'Raise an error (default)'
+          - 'Open a PR'
   push:
     branches:
       - master
@@ -23,7 +32,7 @@ jobs:
     uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1
     with:
       upload_app_binaries_artifact: "ragger_elfs"
-      flags: "CAL_TEST_KEY=1 DOMAIN_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
+      flags: "CAL_TEST_KEY=1 TRUSTED_NAME_TEST_KEY=1 SET_PLUGIN_TEST_KEY=1 NFT_TEST_KEY=1"
 
   ragger_tests:
     name: Run ragger tests using the reusable workflow
@@ -31,6 +40,7 @@ jobs:
     uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1
     with:
       download_app_binaries_artifact: "ragger_elfs"
+      regenerate_snapshots: ${{ inputs.golden_run == 'Open a PR' }}
 
   build_clone_app:
     name: Build Clone app using the reusable workflow
@@ -50,3 +60,4 @@ jobs:
       additional_app_binaries_artifact: "clone_elfs"
       additional_app_binaries_artifact_dir: ./tests/ragger/.test_dependencies/clone/build/
       test_options: "--with_lib_mode"
+      regenerate_snapshots: ${{ inputs.golden_run == 'Open a PR' }}
diff --git a/makefile_conf/chain/tecratestnet.mk b/makefile_conf/chain/tecratestnet.mk
index b778ca1ba..8135f4265 100644
--- a/makefile_conf/chain/tecratestnet.mk
+++ b/makefile_conf/chain/tecratestnet.mk
@@ -1,4 +1,4 @@
-PATH_APP_LOAD_PARAMS += "44'/554'" "44'/60'"
+PATH_APP_LOAD_PARAMS += "44'/554'"
 TICKER = "TCR"
 CHAIN_ID = 20531811
 APPNAME = "TecraTestnet"
diff --git a/tests/ragger/setup.cfg b/tests/ragger/setup.cfg
index 89bf1ed45..4a673e2c3 100644
--- a/tests/ragger/setup.cfg
+++ b/tests/ragger/setup.cfg
@@ -13,6 +13,7 @@ disable = C0114,  # missing-module-docstring
           R0912,  # too-many-branches
           R0913,  # too-many-arguments
           R0914,  # too-many-locals
+          R0915,  # too-many-statements
           W0603,  # global-statement
           E0401   # import-error
 extension-pkg-whitelist=hid
diff --git a/tests/ragger/snapshots/flex/domain_name_wrong_addr/00001.png b/tests/ragger/snapshots/flex/domain_name_wrong_addr/00001.png
deleted file mode 100644
index ed4dc3e5e..000000000
Binary files a/tests/ragger/snapshots/flex/domain_name_wrong_addr/00001.png and /dev/null differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_1/00002.png b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_1/00002.png
index a61e4575a..5ba96b74b 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_1/00002.png and b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_1/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_1/00003.png b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_1/00003.png
index 92d192966..19c095ef1 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_1/00003.png and b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_1/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_137/00002.png b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_137/00002.png
index 62b116d6e..fdedc0698 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_137/00002.png and b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_137/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_137/00003.png b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_137/00003.png
index 9f4c2abc0..28c02bfef 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_137/00003.png and b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_137/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_5/00002.png b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_5/00002.png
index 72b6fdae4..1175fc5f6 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_5/00002.png and b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_5/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_5/00003.png b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_5/00003.png
index 92d192966..19c095ef1 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_5/00003.png and b/tests/ragger/snapshots/flex/erc1155_safeBatchTransferFrom_5/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1-rejected/00002.png b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1-rejected/00002.png
index 1ddb16e24..db789ec72 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1-rejected/00002.png and b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1-rejected/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1-rejected/00003.png b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1-rejected/00003.png
index e4e6c69a0..792681798 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1-rejected/00003.png and b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1-rejected/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1/00002.png b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1/00002.png
index 1ddb16e24..db789ec72 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1/00002.png and b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1/00003.png b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1/00003.png
index e4e6c69a0..792681798 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1/00003.png and b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_1/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_137/00002.png b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_137/00002.png
index ba175d8c5..9621da5af 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_137/00002.png and b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_137/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_137/00003.png b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_137/00003.png
index e141b53ad..13a6b1748 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_137/00003.png and b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_137/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_5/00002.png b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_5/00002.png
index f22f03da6..4c598e730 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_5/00002.png and b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_5/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_5/00003.png b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_5/00003.png
index 527c57cf4..c4ccec35b 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_5/00003.png and b/tests/ragger/snapshots/flex/erc1155_safeTransferFrom_5/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_1/00000.png b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_1/00000.png
index 488291aa0..0c5fa6f32 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_1/00000.png and b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_1/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_1/00001.png b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_1/00001.png
index 085437211..3b910ec77 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_1/00001.png and b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_1/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_137/00000.png b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_137/00000.png
index 3be491860..3e45373cf 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_137/00000.png and b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_137/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_137/00001.png b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_137/00001.png
index f7ea76240..d8e095b1d 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_137/00001.png and b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_137/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_5/00000.png b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_5/00000.png
index fbd37e0cf..f1247b5ce 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_5/00000.png and b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_5/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_5/00001.png b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_5/00001.png
index f7ea76240..d8e095b1d 100644
Binary files a/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_5/00001.png and b/tests/ragger/snapshots/flex/erc1155_setApprovalForAll_5/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_approve_1/00000.png b/tests/ragger/snapshots/flex/erc721_approve_1/00000.png
index 488291aa0..0c5fa6f32 100644
Binary files a/tests/ragger/snapshots/flex/erc721_approve_1/00000.png and b/tests/ragger/snapshots/flex/erc721_approve_1/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_approve_1/00001.png b/tests/ragger/snapshots/flex/erc721_approve_1/00001.png
index 47e56f6b7..d304cefc4 100644
Binary files a/tests/ragger/snapshots/flex/erc721_approve_1/00001.png and b/tests/ragger/snapshots/flex/erc721_approve_1/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_approve_137/00002.png b/tests/ragger/snapshots/flex/erc721_approve_137/00002.png
index f619df540..4cfd36bd7 100644
Binary files a/tests/ragger/snapshots/flex/erc721_approve_137/00002.png and b/tests/ragger/snapshots/flex/erc721_approve_137/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_approve_137/00003.png b/tests/ragger/snapshots/flex/erc721_approve_137/00003.png
index 9f4c2abc0..28c02bfef 100644
Binary files a/tests/ragger/snapshots/flex/erc721_approve_137/00003.png and b/tests/ragger/snapshots/flex/erc721_approve_137/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_approve_5/00002.png b/tests/ragger/snapshots/flex/erc721_approve_5/00002.png
index 00c4c4b86..92cf74df6 100644
Binary files a/tests/ragger/snapshots/flex/erc721_approve_5/00002.png and b/tests/ragger/snapshots/flex/erc721_approve_5/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_approve_5/00003.png b/tests/ragger/snapshots/flex/erc721_approve_5/00003.png
index 92d192966..19c095ef1 100644
Binary files a/tests/ragger/snapshots/flex/erc721_approve_5/00003.png and b/tests/ragger/snapshots/flex/erc721_approve_5/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1-rejected/00000.png b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1-rejected/00000.png
index 548ea6784..dd797e477 100644
Binary files a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1-rejected/00000.png and b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1-rejected/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1-rejected/00001.png b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1-rejected/00001.png
index e9788a1be..49f5d63b5 100644
Binary files a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1-rejected/00001.png and b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1-rejected/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1/00000.png b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1/00000.png
index 548ea6784..dd797e477 100644
Binary files a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1/00000.png and b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1/00001.png b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1/00001.png
index e9788a1be..49f5d63b5 100644
Binary files a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1/00001.png and b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_1/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_137/00002.png b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_137/00002.png
index f619df540..4cfd36bd7 100644
Binary files a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_137/00002.png and b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_137/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_137/00003.png b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_137/00003.png
index 9f4c2abc0..28c02bfef 100644
Binary files a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_137/00003.png and b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_137/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_5/00002.png b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_5/00002.png
index 00c4c4b86..92cf74df6 100644
Binary files a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_5/00002.png and b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_5/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_5/00003.png b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_5/00003.png
index 92d192966..19c095ef1 100644
Binary files a/tests/ragger/snapshots/flex/erc721_safeTransferFrom_5/00003.png and b/tests/ragger/snapshots/flex/erc721_safeTransferFrom_5/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_1/00000.png b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_1/00000.png
index 488291aa0..0c5fa6f32 100644
Binary files a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_1/00000.png and b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_1/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_1/00001.png b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_1/00001.png
index 20f4fa457..213e7bcb4 100644
Binary files a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_1/00001.png and b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_1/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_137/00000.png b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_137/00000.png
index 3be491860..3e45373cf 100644
Binary files a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_137/00000.png and b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_137/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_137/00001.png b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_137/00001.png
index 9ac9a4bc6..0c1f907fc 100644
Binary files a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_137/00001.png and b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_137/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_5/00000.png b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_5/00000.png
index fbd37e0cf..f1247b5ce 100644
Binary files a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_5/00000.png and b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_5/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_5/00001.png b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_5/00001.png
index a55097529..b33f490fb 100644
Binary files a/tests/ragger/snapshots/flex/erc721_setApprovalForAll_5/00001.png and b/tests/ragger/snapshots/flex/erc721_setApprovalForAll_5/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_transferFrom_1/00000.png b/tests/ragger/snapshots/flex/erc721_transferFrom_1/00000.png
index 548ea6784..dd797e477 100644
Binary files a/tests/ragger/snapshots/flex/erc721_transferFrom_1/00000.png and b/tests/ragger/snapshots/flex/erc721_transferFrom_1/00000.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_transferFrom_1/00001.png b/tests/ragger/snapshots/flex/erc721_transferFrom_1/00001.png
index e9788a1be..49f5d63b5 100644
Binary files a/tests/ragger/snapshots/flex/erc721_transferFrom_1/00001.png and b/tests/ragger/snapshots/flex/erc721_transferFrom_1/00001.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_transferFrom_137/00002.png b/tests/ragger/snapshots/flex/erc721_transferFrom_137/00002.png
index f619df540..4cfd36bd7 100644
Binary files a/tests/ragger/snapshots/flex/erc721_transferFrom_137/00002.png and b/tests/ragger/snapshots/flex/erc721_transferFrom_137/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_transferFrom_137/00003.png b/tests/ragger/snapshots/flex/erc721_transferFrom_137/00003.png
index 9f4c2abc0..28c02bfef 100644
Binary files a/tests/ragger/snapshots/flex/erc721_transferFrom_137/00003.png and b/tests/ragger/snapshots/flex/erc721_transferFrom_137/00003.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_transferFrom_5/00002.png b/tests/ragger/snapshots/flex/erc721_transferFrom_5/00002.png
index 00c4c4b86..92cf74df6 100644
Binary files a/tests/ragger/snapshots/flex/erc721_transferFrom_5/00002.png and b/tests/ragger/snapshots/flex/erc721_transferFrom_5/00002.png differ
diff --git a/tests/ragger/snapshots/flex/erc721_transferFrom_5/00003.png b/tests/ragger/snapshots/flex/erc721_transferFrom_5/00003.png
index 92d192966..19c095ef1 100644
Binary files a/tests/ragger/snapshots/flex/erc721_transferFrom_5/00003.png and b/tests/ragger/snapshots/flex/erc721_transferFrom_5/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_blind_sign_rejected/00000.png b/tests/ragger/snapshots/flex/test_blind_sign_rejected/00000.png
index 4397e0e07..acbb161df 100644
Binary files a/tests/ragger/snapshots/flex/test_blind_sign_rejected/00000.png and b/tests/ragger/snapshots/flex/test_blind_sign_rejected/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_blind_sign_rejected/00001.png b/tests/ragger/snapshots/flex/test_blind_sign_rejected/00001.png
index 8949bed74..a36989ec6 100644
Binary files a/tests/ragger/snapshots/flex/test_blind_sign_rejected/00001.png and b/tests/ragger/snapshots/flex/test_blind_sign_rejected/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_blind_sign_rejected/00002.png b/tests/ragger/snapshots/flex/test_blind_sign_rejected/00002.png
index 2b71d8212..cf3b20e5b 100644
Binary files a/tests/ragger/snapshots/flex/test_blind_sign_rejected/00002.png and b/tests/ragger/snapshots/flex/test_blind_sign_rejected/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_blind_sign_signed/00000.png b/tests/ragger/snapshots/flex/test_blind_sign_signed/00000.png
index 4397e0e07..acbb161df 100644
Binary files a/tests/ragger/snapshots/flex/test_blind_sign_signed/00000.png and b/tests/ragger/snapshots/flex/test_blind_sign_signed/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_blind_sign_signed/00001.png b/tests/ragger/snapshots/flex/test_blind_sign_signed/00001.png
index 8949bed74..a36989ec6 100644
Binary files a/tests/ragger/snapshots/flex/test_blind_sign_signed/00001.png and b/tests/ragger/snapshots/flex/test_blind_sign_signed/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_blind_sign_signed/00002.png b/tests/ragger/snapshots/flex/test_blind_sign_signed/00002.png
index 2b71d8212..cf3b20e5b 100644
Binary files a/tests/ragger/snapshots/flex/test_blind_sign_signed/00002.png and b/tests/ragger/snapshots/flex/test_blind_sign_signed/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_clone_thundercore/00000.png b/tests/ragger/snapshots/flex/test_clone_thundercore/00000.png
index 238e38148..6ff18c641 100644
Binary files a/tests/ragger/snapshots/flex/test_clone_thundercore/00000.png and b/tests/ragger/snapshots/flex/test_clone_thundercore/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_clone_thundercore/00001.png b/tests/ragger/snapshots/flex/test_clone_thundercore/00001.png
index 618815bef..636ba701a 100644
Binary files a/tests/ragger/snapshots/flex/test_clone_thundercore/00001.png and b/tests/ragger/snapshots/flex/test_clone_thundercore/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00001.png
new file mode 100644
index 000000000..ca4567bf7
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-False-True/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00001.png
new file mode 100644
index 000000000..d2b6f4138
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_missing_token-True-False/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00001.png
new file mode 100644
index 000000000..897ec3706
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png
new file mode 100644
index 000000000..897ec3706
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00001.png
new file mode 100644
index 000000000..015f0dfdf
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png
new file mode 100644
index 000000000..897ec3706
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00001.png
new file mode 100644
index 000000000..015f0dfdf
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png
new file mode 100644
index 000000000..00fcc93ac
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00001.png
new file mode 100644
index 000000000..00fcc93ac
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png
new file mode 100644
index 000000000..00fcc93ac
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00000.png b/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00000.png
new file mode 100644
index 000000000..14713d83b
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00001.png b/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00001.png
new file mode 100644
index 000000000..7d202e913
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00002.png b/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00002.png
new file mode 100644
index 000000000..cbaa88901
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00003.png b/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00003.png
new file mode 100644
index 000000000..8b981d44c
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_eip712_filtering_empty_array/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_legacy_chainid/00000.png b/tests/ragger/snapshots/flex/test_legacy_chainid/00000.png
index 7dc2eae68..e7a72e7fb 100644
Binary files a/tests/ragger/snapshots/flex/test_legacy_chainid/00000.png and b/tests/ragger/snapshots/flex/test_legacy_chainid/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_legacy_chainid/00001.png b/tests/ragger/snapshots/flex/test_legacy_chainid/00001.png
index ae8de1f1c..9eb958d49 100644
Binary files a/tests/ragger/snapshots/flex/test_legacy_chainid/00001.png and b/tests/ragger/snapshots/flex/test_legacy_chainid/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_legacy_send_bsc/00000.png b/tests/ragger/snapshots/flex/test_legacy_send_bsc/00000.png
index c3c7c83a3..5166ee6c3 100644
Binary files a/tests/ragger/snapshots/flex/test_legacy_send_bsc/00000.png and b/tests/ragger/snapshots/flex/test_legacy_send_bsc/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_legacy_send_bsc/00001.png b/tests/ragger/snapshots/flex/test_legacy_send_bsc/00001.png
index 898ca23b1..7c58a7a44 100644
Binary files a/tests/ragger/snapshots/flex/test_legacy_send_bsc/00001.png and b/tests/ragger/snapshots/flex/test_legacy_send_bsc/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_eip_2930/00000.png b/tests/ragger/snapshots/flex/test_sign_eip_2930/00000.png
index 2cd4319e2..275ae3ac9 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_eip_2930/00000.png and b/tests/ragger/snapshots/flex/test_sign_eip_2930/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_eip_2930/00001.png b/tests/ragger/snapshots/flex/test_sign_eip_2930/00001.png
index 4b571d159..fc84a157e 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_eip_2930/00001.png and b/tests/ragger/snapshots/flex/test_sign_eip_2930/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_limit_nonce/00000.png b/tests/ragger/snapshots/flex/test_sign_limit_nonce/00000.png
index 2cd4319e2..275ae3ac9 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_limit_nonce/00000.png and b/tests/ragger/snapshots/flex/test_sign_limit_nonce/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_limit_nonce/00001.png b/tests/ragger/snapshots/flex/test_sign_limit_nonce/00001.png
index a348217e4..bda633b3a 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_limit_nonce/00001.png and b/tests/ragger/snapshots/flex/test_sign_limit_nonce/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_nonce_display/00000.png b/tests/ragger/snapshots/flex/test_sign_nonce_display/00000.png
index 2cd4319e2..275ae3ac9 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_nonce_display/00000.png and b/tests/ragger/snapshots/flex/test_sign_nonce_display/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_nonce_display/00001.png b/tests/ragger/snapshots/flex/test_sign_nonce_display/00001.png
index 99c4c4673..b65a78b41 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_nonce_display/00001.png and b/tests/ragger/snapshots/flex/test_sign_nonce_display/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00000.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00000.png
index d614f30f5..eb6139b20 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00000.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00001.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00001.png
index 616945d85..b991ceb21 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00001.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00003.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00003.png
index ec8d2e657..48fd55291 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00003.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00004.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00004.png
index 645a768dd..d1bf336fe 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00004.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00004.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00006.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00006.png
index ec8d2e657..48fd55291 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00006.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00006.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00007.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00007.png
index b022c9fbc..5cf8178e8 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00007.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00007.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00009.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00009.png
index 4397e0e07..acbb161df 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00009.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00009.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00010.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00010.png
index 8949bed74..a36989ec6 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00010.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00010.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00011.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00011.png
index 2b71d8212..cf3b20e5b 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00011.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00011.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_reject/00000.png b/tests/ragger/snapshots/flex/test_sign_reject/00000.png
index 2cd4319e2..275ae3ac9 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_reject/00000.png and b/tests/ragger/snapshots/flex/test_sign_reject/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_reject/00001.png b/tests/ragger/snapshots/flex/test_sign_reject/00001.png
index 99c4c4673..b65a78b41 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_reject/00001.png and b/tests/ragger/snapshots/flex/test_sign_reject/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_simple/00000.png b/tests/ragger/snapshots/flex/test_sign_simple/00000.png
index 2cd4319e2..275ae3ac9 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_simple/00000.png and b/tests/ragger/snapshots/flex/test_sign_simple/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_sign_simple/00001.png b/tests/ragger/snapshots/flex/test_sign_simple/00001.png
index 99c4c4673..b65a78b41 100644
Binary files a/tests/ragger/snapshots/flex/test_sign_simple/00001.png and b/tests/ragger/snapshots/flex/test_sign_simple/00001.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_wrong_addr/00000.png b/tests/ragger/snapshots/flex/test_trusted_name_v1/00000.png
similarity index 77%
rename from tests/ragger/snapshots/flex/domain_name_wrong_addr/00000.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1/00000.png
index 2cd4319e2..275ae3ac9 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_wrong_addr/00000.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1/00000.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_True/00001.png b/tests/ragger/snapshots/flex/test_trusted_name_v1/00001.png
similarity index 86%
rename from tests/ragger/snapshots/flex/domain_name_verbose_True/00001.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1/00001.png
index 77e339b5d..12e12ece6 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_verbose_True/00001.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1/00001.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_False/00002.png b/tests/ragger/snapshots/flex/test_trusted_name_v1/00002.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_verbose_False/00002.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1/00002.png
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_False/00003.png b/tests/ragger/snapshots/flex/test_trusted_name_v1/00003.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_verbose_False/00003.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1/00003.png
diff --git a/tests/ragger/snapshots/flex/domain_name_non_mainnet/00004.png b/tests/ragger/snapshots/flex/test_trusted_name_v1/00004.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_non_mainnet/00004.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1/00004.png
diff --git a/tests/ragger/snapshots/flex/domain_name_non_mainnet/00005.png b/tests/ragger/snapshots/flex/test_trusted_name_v1/00005.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_non_mainnet/00005.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1/00005.png
diff --git a/tests/ragger/snapshots/flex/domain_name_non_mainnet/00000.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00000.png
similarity index 75%
rename from tests/ragger/snapshots/flex/domain_name_non_mainnet/00000.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00000.png
index 386de6115..b42faf7f8 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_non_mainnet/00000.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00000.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_non_mainnet/00001.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00001.png
similarity index 86%
rename from tests/ragger/snapshots/flex/domain_name_non_mainnet/00001.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00001.png
index 77e339b5d..12e12ece6 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_non_mainnet/00001.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00001.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_non_mainnet/00002.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00002.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_non_mainnet/00002.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00002.png
diff --git a/tests/ragger/snapshots/flex/domain_name_non_mainnet/00003.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00003.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_non_mainnet/00003.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00003.png
diff --git a/tests/ragger/snapshots/flex/domain_name_unknown_chain/00004.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00004.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_unknown_chain/00004.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00004.png
diff --git a/tests/ragger/snapshots/flex/domain_name_unknown_chain/00005.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00005.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_unknown_chain/00005.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_non_mainnet/00005.png
diff --git a/tests/ragger/snapshots/flex/domain_name_unknown_chain/00000.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00000.png
similarity index 75%
rename from tests/ragger/snapshots/flex/domain_name_unknown_chain/00000.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00000.png
index 7dc2eae68..e7a72e7fb 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_unknown_chain/00000.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00000.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_unknown_chain/00001.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00001.png
similarity index 89%
rename from tests/ragger/snapshots/flex/domain_name_unknown_chain/00001.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00001.png
index bb69fdc1d..075e3efc8 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_unknown_chain/00001.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00001.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_unknown_chain/00002.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00002.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_unknown_chain/00002.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00002.png
diff --git a/tests/ragger/snapshots/flex/domain_name_unknown_chain/00003.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00003.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_unknown_chain/00003.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00003.png
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_False/00004.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00004.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_verbose_False/00004.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00004.png
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_False/00005.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00005.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_verbose_False/00005.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_unknown_chain/00005.png
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_True/00000.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00000.png
similarity index 77%
rename from tests/ragger/snapshots/flex/domain_name_verbose_True/00000.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00000.png
index 2cd4319e2..275ae3ac9 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_verbose_True/00000.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00000.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_False/00001.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00001.png
similarity index 86%
rename from tests/ragger/snapshots/flex/domain_name_verbose_False/00001.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00001.png
index 77e339b5d..12e12ece6 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_verbose_False/00001.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00001.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_True/00002.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00002.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_verbose_True/00002.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00002.png
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_True/00003.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00003.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_verbose_True/00003.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00003.png
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_True/00004.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00004.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_verbose_True/00004.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00004.png
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_True/00005.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00005.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_verbose_True/00005.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_verbose/00005.png
diff --git a/tests/ragger/snapshots/flex/domain_name_verbose_False/00000.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00000.png
similarity index 77%
rename from tests/ragger/snapshots/flex/domain_name_verbose_False/00000.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00000.png
index 2cd4319e2..275ae3ac9 100644
Binary files a/tests/ragger/snapshots/flex/domain_name_verbose_False/00000.png and b/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00001.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00001.png
new file mode 100644
index 000000000..8bd3bd71f
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00001.png differ
diff --git a/tests/ragger/snapshots/flex/domain_name_wrong_addr/00002.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00002.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_wrong_addr/00002.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00002.png
diff --git a/tests/ragger/snapshots/flex/domain_name_wrong_addr/00003.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00003.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_wrong_addr/00003.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00003.png
diff --git a/tests/ragger/snapshots/flex/domain_name_wrong_addr/00004.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00004.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_wrong_addr/00004.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00004.png
diff --git a/tests/ragger/snapshots/flex/domain_name_wrong_addr/00005.png b/tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00005.png
similarity index 100%
rename from tests/ragger/snapshots/flex/domain_name_wrong_addr/00005.png
rename to tests/ragger/snapshots/flex/test_trusted_name_v1_wrong_addr/00005.png
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2/00000.png b/tests/ragger/snapshots/flex/test_trusted_name_v2/00000.png
new file mode 100644
index 000000000..275ae3ac9
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2/00001.png b/tests/ragger/snapshots/flex/test_trusted_name_v2/00001.png
new file mode 100644
index 000000000..12e12ece6
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2/00002.png b/tests/ragger/snapshots/flex/test_trusted_name_v2/00002.png
new file mode 100644
index 000000000..76e3e706e
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2/00003.png b/tests/ragger/snapshots/flex/test_trusted_name_v2/00003.png
new file mode 100644
index 000000000..99abe61b4
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2/00004.png b/tests/ragger/snapshots/flex/test_trusted_name_v2/00004.png
new file mode 100644
index 000000000..be51a9d55
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2/00004.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2/00005.png b/tests/ragger/snapshots/flex/test_trusted_name_v2/00005.png
new file mode 100644
index 000000000..dabe7afea
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2/00005.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00000.png b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00000.png
new file mode 100644
index 000000000..e7a72e7fb
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00000.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00001.png b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00001.png
new file mode 100644
index 000000000..075e3efc8
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00001.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00002.png b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00002.png
new file mode 100644
index 000000000..b71bb8de5
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00002.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00003.png b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00003.png
new file mode 100644
index 000000000..d5808be42
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00003.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00004.png b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00004.png
new file mode 100644
index 000000000..be51a9d55
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00004.png differ
diff --git a/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00005.png b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00005.png
new file mode 100644
index 000000000..dabe7afea
Binary files /dev/null and b/tests/ragger/snapshots/flex/test_trusted_name_v2_wrong_chainid/00005.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00001.png
new file mode 100644
index 000000000..2d21c88f4
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00002.png
new file mode 100644
index 000000000..f27e25bb7
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00003.png
new file mode 100644
index 000000000..64f9f3c7f
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00007.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00007.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-False-True/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00001.png
new file mode 100644
index 000000000..2d21c88f4
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00002.png
new file mode 100644
index 000000000..864ee3753
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00003.png
new file mode 100644
index 000000000..087939498
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00007.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00007.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_missing_token-True-False/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00002.png
new file mode 100644
index 000000000..dbbd8b2b6
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00006.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_False/00006.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png
new file mode 100644
index 000000000..dbbd8b2b6
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00007.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_True/00007.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_account_contract/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00002.png
new file mode 100644
index 000000000..c6c7b417f
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00006.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00006.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png
new file mode 100644
index 000000000..dbbd8b2b6
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00007.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_non_mainnet/00007.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_account_with_contract_account/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00002.png
new file mode 100644
index 000000000..c6c7b417f
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00007.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_unknown_chain/00007.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png
new file mode 100644
index 000000000..2690b42f7
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00006.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_False/00006.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_account_contract/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00002.png
new file mode 100644
index 000000000..2690b42f7
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00007.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_True/00007.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png
new file mode 100644
index 000000000..2690b42f7
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00006.png b/tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_wrong_addr/00006.png
rename to tests/ragger/snapshots/nanosp/test_eip712_advanced_trusted_name_contract_with_contract_account/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00000.png b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00000.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00001.png b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00001.png
new file mode 100644
index 000000000..9bc9e1ed7
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00001.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00002.png b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00002.png
new file mode 100644
index 000000000..f070aac76
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00002.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00003.png b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00003.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00003.png differ
diff --git a/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00004.png b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00004.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_eip712_filtering_empty_array/00004.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00000.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00000.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1/00000.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00001.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00001.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1/00001.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00002.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00002.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1/00002.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00003.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00003.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1/00003.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00004.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_False/00004.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1/00004.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00005.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_False/00005.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00006.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00006.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_trusted_name_v1/00006.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00000.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00000.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00000.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00001.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00001.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00001.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00002.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_False/00002.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00002.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00003.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_False/00003.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00003.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00004.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00004.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00004.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00005.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00005.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00005.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00006.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00006.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_non_mainnet/00006.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00006.png
diff --git a/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00007.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00007.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_non_mainnet/00007.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00000.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_False/00000.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00000.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_False/00001.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_False/00001.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00001.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00002.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00002.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00002.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00003.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00003.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00003.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00004.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00004.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00004.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00005.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00005.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00005.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00006.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00006.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_unknown_chain/00006.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00006.png
diff --git a/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00007.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00007.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_unknown_chain/00007.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00000.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_True/00000.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00000.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00001.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_True/00001.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00001.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00002.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_True/00002.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00002.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00003.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_True/00003.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00003.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00004.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_True/00004.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00004.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00005.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_True/00005.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00005.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_verbose_True/00006.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00006.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_verbose_True/00006.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00006.png
diff --git a/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00007.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00007.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_verbose/00007.png differ
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00000.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00000.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00000.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00001.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00001.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00001.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00002.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00002.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00002.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00003.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00003.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00003.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00004.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00004.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00004.png
diff --git a/tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00005.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanosp/domain_name_wrong_addr/00005.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00006.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00006.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_trusted_name_v1_wrong_addr/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00000.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_non_mainnet/00000.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2/00000.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00001.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_non_mainnet/00001.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2/00001.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2/00002.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00003.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_non_mainnet/00003.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2/00003.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00004.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_False/00004.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2/00004.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00005.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_False/00005.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2/00005.png
diff --git a/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00006.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00006.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_trusted_name_v2/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00000.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_unknown_chain/00000.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00000.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00001.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_unknown_chain/00001.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00001.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00002.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_unknown_chain/00002.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00002.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00003.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_unknown_chain/00003.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00003.png
diff --git a/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00004.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00004.png
new file mode 100644
index 000000000..de64317f3
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00005.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_unknown_chain/00005.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00005.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00006.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00006.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_non_mainnet/00006.png
rename to tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00006.png
diff --git a/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00007.png b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00007.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanosp/test_trusted_name_v2_wrong_chainid/00007.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00001.png
new file mode 100644
index 000000000..2d21c88f4
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00002.png
new file mode 100644
index 000000000..f27e25bb7
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00003.png
new file mode 100644
index 000000000..64f9f3c7f
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-False-True/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00001.png
new file mode 100644
index 000000000..2d21c88f4
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00002.png
new file mode 100644
index 000000000..864ee3753
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00003.png
new file mode 100644
index 000000000..087939498
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_missing_token-True-False/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00002.png
new file mode 100644
index 000000000..dbbd8b2b6
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png
new file mode 100644
index 000000000..dbbd8b2b6
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_account_contract/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00002.png
new file mode 100644
index 000000000..c6c7b417f
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png
new file mode 100644
index 000000000..dbbd8b2b6
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_account_with_contract_account/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00002.png
new file mode 100644
index 000000000..c6c7b417f
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png
new file mode 100644
index 000000000..2690b42f7
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_account_contract/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00002.png
new file mode 100644
index 000000000..2690b42f7
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png
new file mode 100644
index 000000000..3f56240b5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png
new file mode 100644
index 000000000..2690b42f7
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png
new file mode 100644
index 000000000..52c69d641
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00004.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00004.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00005.png b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00005.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_advanced_trusted_name_contract_with_contract_account/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00000.png b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00000.png
new file mode 100644
index 000000000..b546f65af
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00001.png b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00001.png
new file mode 100644
index 000000000..9bc9e1ed7
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00002.png b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00002.png
new file mode 100644
index 000000000..f070aac76
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00003.png b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00003.png
new file mode 100644
index 000000000..53ae65195
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00004.png b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00004.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_eip712_filtering_empty_array/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00000.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_False/00000.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1/00000.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00001.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_False/00001.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1/00001.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00002.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_False/00002.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1/00002.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00003.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_False/00003.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1/00003.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00004.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_wrong_addr/00004.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1/00004.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00005.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_wrong_addr/00005.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1/00005.png
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1/00006.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1/00006.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00000.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_True/00000.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00000.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00001.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_True/00001.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00001.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00002.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_True/00002.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00002.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00003.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_True/00003.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00003.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00004.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00005.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_non_mainnet/00005.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00005.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00006.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00006.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_unknown_chain/00006.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00006.png
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00007.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00007.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_non_mainnet/00007.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00000.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00000.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_wrong_addr/00000.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00000.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00001.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00001.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_wrong_addr/00001.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00001.png
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00002.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00002.png
new file mode 100644
index 000000000..23d61ed89
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00003.png
diff --git a/tests/ragger/snapshots/nanox/domain_name_unknown_chain/00004.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00004.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_unknown_chain/00004.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00004.png
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00005.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00005.png
new file mode 100644
index 000000000..c2a8d9070
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00006.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00006.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_True/00006.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00006.png
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00007.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00007.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_unknown_chain/00007.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00000.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00001.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00001.png
new file mode 100644
index 000000000..1ac2ab077
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00002.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00002.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_wrong_addr/00002.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00002.png
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00003.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00003.png
new file mode 100644
index 000000000..a74d347ce
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00004.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00004.png
new file mode 100644
index 000000000..375301fcc
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00005.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00005.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_verbose_True/00005.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00005.png
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00006.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00006.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00007.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00007.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_verbose/00007.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00000.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00001.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00001.png
new file mode 100644
index 000000000..1ac2ab077
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00002.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00002.png
new file mode 100644
index 000000000..f9840e3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00003.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00003.png
similarity index 100%
rename from tests/ragger/snapshots/nanox/domain_name_wrong_addr/00003.png
rename to tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00003.png
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00004.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00004.png
new file mode 100644
index 000000000..1bcb78761
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00005.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00005.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00006.png b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00006.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v1_wrong_addr/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2/00000.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2/00001.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00001.png
new file mode 100644
index 000000000..1ac2ab077
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2/00002.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00002.png
new file mode 100644
index 000000000..f9840e3ab
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2/00003.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00003.png
new file mode 100644
index 000000000..a74d347ce
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2/00004.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00004.png
new file mode 100644
index 000000000..1bcb78761
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2/00005.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00005.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2/00006.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00006.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00000.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00000.png
new file mode 100644
index 000000000..487ea10fc
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00000.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00001.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00001.png
new file mode 100644
index 000000000..1ac2ab077
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00001.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00002.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00002.png
new file mode 100644
index 000000000..23d61ed89
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00002.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00003.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00003.png
new file mode 100644
index 000000000..375301fcc
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00003.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00004.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00004.png
new file mode 100644
index 000000000..de64317f3
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00004.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00005.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00005.png
new file mode 100644
index 000000000..c2a8d9070
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00005.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00006.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00006.png
new file mode 100644
index 000000000..570ce28d5
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00006.png differ
diff --git a/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00007.png b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00007.png
new file mode 100644
index 000000000..657887225
Binary files /dev/null and b/tests/ragger/snapshots/nanox/test_trusted_name_v2_wrong_chainid/00007.png differ
diff --git a/tests/ragger/snapshots/stax/get_pk_1/00001.png b/tests/ragger/snapshots/stax/get_pk_1/00001.png
index 74e666deb..4694f41e0 100644
Binary files a/tests/ragger/snapshots/stax/get_pk_1/00001.png and b/tests/ragger/snapshots/stax/get_pk_1/00001.png differ
diff --git a/tests/ragger/snapshots/stax/get_pk_137/00001.png b/tests/ragger/snapshots/stax/get_pk_137/00001.png
index 74e666deb..4694f41e0 100644
Binary files a/tests/ragger/snapshots/stax/get_pk_137/00001.png and b/tests/ragger/snapshots/stax/get_pk_137/00001.png differ
diff --git a/tests/ragger/snapshots/stax/get_pk_2/00001.png b/tests/ragger/snapshots/stax/get_pk_2/00001.png
index 74e666deb..4694f41e0 100644
Binary files a/tests/ragger/snapshots/stax/get_pk_2/00001.png and b/tests/ragger/snapshots/stax/get_pk_2/00001.png differ
diff --git a/tests/ragger/snapshots/stax/get_pk_5/00001.png b/tests/ragger/snapshots/stax/get_pk_5/00001.png
index 74e666deb..4694f41e0 100644
Binary files a/tests/ragger/snapshots/stax/get_pk_5/00001.png and b/tests/ragger/snapshots/stax/get_pk_5/00001.png differ
diff --git a/tests/ragger/snapshots/stax/get_pk_None/00001.png b/tests/ragger/snapshots/stax/get_pk_None/00001.png
index 74e666deb..4694f41e0 100644
Binary files a/tests/ragger/snapshots/stax/get_pk_None/00001.png and b/tests/ragger/snapshots/stax/get_pk_None/00001.png differ
diff --git a/tests/ragger/snapshots/stax/get_pk_rejected_60/00001.png b/tests/ragger/snapshots/stax/get_pk_rejected_60/00001.png
index 74e666deb..4694f41e0 100644
Binary files a/tests/ragger/snapshots/stax/get_pk_rejected_60/00001.png and b/tests/ragger/snapshots/stax/get_pk_rejected_60/00001.png differ
diff --git a/tests/ragger/snapshots/stax/get_pk_rejected_700/00001.png b/tests/ragger/snapshots/stax/get_pk_rejected_700/00001.png
index 59b34f611..901d45f08 100644
Binary files a/tests/ragger/snapshots/stax/get_pk_rejected_700/00001.png and b/tests/ragger/snapshots/stax/get_pk_rejected_700/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_blind_sign_rejected/00000.png b/tests/ragger/snapshots/stax/test_blind_sign_rejected/00000.png
index 04055db7b..9696ae123 100644
Binary files a/tests/ragger/snapshots/stax/test_blind_sign_rejected/00000.png and b/tests/ragger/snapshots/stax/test_blind_sign_rejected/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_blind_sign_signed/00000.png b/tests/ragger/snapshots/stax/test_blind_sign_signed/00000.png
index 04055db7b..9696ae123 100644
Binary files a/tests/ragger/snapshots/stax/test_blind_sign_signed/00000.png and b/tests/ragger/snapshots/stax/test_blind_sign_signed/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00001.png
new file mode 100644
index 000000000..85b8c5362
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-False-True/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00001.png
new file mode 100644
index 000000000..ae760ec38
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_missing_token-True-False/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00001.png
new file mode 100644
index 000000000..356c1897f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png
new file mode 100644
index 000000000..356c1897f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_account_contract/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00001.png
new file mode 100644
index 000000000..225f6427e
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png
new file mode 100644
index 000000000..356c1897f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_account_with_contract_account/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00001.png
new file mode 100644
index 000000000..225f6427e
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png
new file mode 100644
index 000000000..9beedee22
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_account_contract/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00001.png
new file mode 100644
index 000000000..9beedee22
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png
new file mode 100644
index 000000000..9beedee22
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_advanced_trusted_name_contract_with_contract_account/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00000.png b/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00000.png
new file mode 100644
index 000000000..eb8072d46
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00001.png b/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00001.png
new file mode 100644
index 000000000..efce2dfe6
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00002.png b/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00002.png
new file mode 100644
index 000000000..fbea72d8f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00003.png b/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00003.png
new file mode 100644
index 000000000..cfee3aec2
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_eip712_filtering_empty_array/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_get_eth2_pk/00001.png b/tests/ragger/snapshots/stax/test_get_eth2_pk/00001.png
index 4a25c17a1..dfa82ea9a 100644
Binary files a/tests/ragger/snapshots/stax/test_get_eth2_pk/00001.png and b/tests/ragger/snapshots/stax/test_get_eth2_pk/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_personal_sign_opensea/00001.png b/tests/ragger/snapshots/stax/test_personal_sign_opensea/00001.png
index 095e8617f..dac41f2d6 100644
Binary files a/tests/ragger/snapshots/stax/test_personal_sign_opensea/00001.png and b/tests/ragger/snapshots/stax/test_personal_sign_opensea/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_personal_sign_opensea/00002.png b/tests/ragger/snapshots/stax/test_personal_sign_opensea/00002.png
index 4bed4ebec..aad415f04 100644
Binary files a/tests/ragger/snapshots/stax/test_personal_sign_opensea/00002.png and b/tests/ragger/snapshots/stax/test_personal_sign_opensea/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_sign_parameter_selector/00009.png b/tests/ragger/snapshots/stax/test_sign_parameter_selector/00009.png
index 04055db7b..9696ae123 100644
Binary files a/tests/ragger/snapshots/stax/test_sign_parameter_selector/00009.png and b/tests/ragger/snapshots/stax/test_sign_parameter_selector/00009.png differ
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00000.png b/tests/ragger/snapshots/stax/test_trusted_name_v1/00000.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_False/00000.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1/00000.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00001.png b/tests/ragger/snapshots/stax/test_trusted_name_v1/00001.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_False/00001.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1/00001.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00002.png b/tests/ragger/snapshots/stax/test_trusted_name_v1/00002.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_False/00002.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1/00002.png
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00003.png b/tests/ragger/snapshots/stax/test_trusted_name_v1/00003.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_non_mainnet/00003.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1/00003.png
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00004.png b/tests/ragger/snapshots/stax/test_trusted_name_v1/00004.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_non_mainnet/00004.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1/00004.png
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00005.png b/tests/ragger/snapshots/stax/test_trusted_name_v1/00005.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_non_mainnet/00005.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1/00005.png
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00000.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00000.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_non_mainnet/00000.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00000.png
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00001.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00001.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_non_mainnet/00001.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00001.png
diff --git a/tests/ragger/snapshots/stax/domain_name_non_mainnet/00002.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00002.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_non_mainnet/00002.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00002.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00003.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00003.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_False/00003.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00003.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00004.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00004.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_False/00004.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00004.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_False/00005.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00005.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_False/00005.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_non_mainnet/00005.png
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00000.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00000.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_unknown_chain/00000.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00000.png
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00001.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00001.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_unknown_chain/00001.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00001.png
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00002.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00002.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_unknown_chain/00002.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00002.png
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00003.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00003.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_unknown_chain/00003.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00003.png
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00004.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00004.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_unknown_chain/00004.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00004.png
diff --git a/tests/ragger/snapshots/stax/domain_name_unknown_chain/00005.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00005.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_unknown_chain/00005.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_unknown_chain/00005.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00000.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00000.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_True/00000.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00000.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00001.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00001.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_True/00001.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00001.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00002.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00002.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_True/00002.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00002.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00003.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00003.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_True/00003.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00003.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00004.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00004.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_True/00004.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00004.png
diff --git a/tests/ragger/snapshots/stax/domain_name_verbose_True/00005.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00005.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_verbose_True/00005.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_verbose/00005.png
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00000.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00000.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_wrong_addr/00000.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00000.png
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00001.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00001.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_wrong_addr/00001.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00001.png
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00002.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00002.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_wrong_addr/00002.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00002.png
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00003.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00003.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_wrong_addr/00003.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00003.png
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00004.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00004.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_wrong_addr/00004.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00004.png
diff --git a/tests/ragger/snapshots/stax/domain_name_wrong_addr/00005.png b/tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00005.png
similarity index 100%
rename from tests/ragger/snapshots/stax/domain_name_wrong_addr/00005.png
rename to tests/ragger/snapshots/stax/test_trusted_name_v1_wrong_addr/00005.png
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2/00000.png b/tests/ragger/snapshots/stax/test_trusted_name_v2/00000.png
new file mode 100644
index 000000000..646ad0e00
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2/00001.png b/tests/ragger/snapshots/stax/test_trusted_name_v2/00001.png
new file mode 100644
index 000000000..0129b9230
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2/00002.png b/tests/ragger/snapshots/stax/test_trusted_name_v2/00002.png
new file mode 100644
index 000000000..d3fa2f494
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2/00003.png b/tests/ragger/snapshots/stax/test_trusted_name_v2/00003.png
new file mode 100644
index 000000000..392165d4f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2/00004.png b/tests/ragger/snapshots/stax/test_trusted_name_v2/00004.png
new file mode 100644
index 000000000..339db1b45
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2/00004.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00000.png b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00000.png
new file mode 100644
index 000000000..b861aca15
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00000.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00001.png b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00001.png
new file mode 100644
index 000000000..36cae6f09
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00001.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00002.png b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00002.png
new file mode 100644
index 000000000..b1c573784
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00002.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00003.png b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00003.png
new file mode 100644
index 000000000..e91c22224
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00003.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00004.png b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00004.png
new file mode 100644
index 000000000..392165d4f
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00004.png differ
diff --git a/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00005.png b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00005.png
new file mode 100644
index 000000000..339db1b45
Binary files /dev/null and b/tests/ragger/snapshots/stax/test_trusted_name_v2_wrong_chainid/00005.png differ
diff --git a/tests/ragger/test_blind_sign.py b/tests/ragger/test_blind_sign.py
index 8be4e0cd9..cb2568718 100644
--- a/tests/ragger/test_blind_sign.py
+++ b/tests/ragger/test_blind_sign.py
@@ -34,7 +34,7 @@ def common_tx_params() -> dict:
             abi=json.load(file),
             address=None
         )
-    data = contract.encodeABI("approve", [
+    data = contract.encode_abi("approve", [
         # Uniswap Protocol: Permit2
         bytes.fromhex("000000000022d473030f116ddee9f6b43ac78ba3"),
         Web3.to_wei("2", "ether")
diff --git a/tests/ragger/test_domain_name.py b/tests/ragger/test_domain_name.py
deleted file mode 100644
index 96fa27023..000000000
--- a/tests/ragger/test_domain_name.py
+++ /dev/null
@@ -1,191 +0,0 @@
-import pytest
-from web3 import Web3
-
-from ragger.backend import BackendInterface
-from ragger.firmware import Firmware
-from ragger.error import ExceptionRAPDU
-from ragger.navigator import Navigator
-from ragger.navigator.navigation_scenario import NavigateWithScenario
-
-import client.response_parser as ResponseParser
-from client.client import EthAppClient, StatusWord
-from client.settings import SettingID, settings_toggle
-
-
-# Values used across all tests
-CHAIN_ID = 1
-NAME = "ledger.eth"
-ADDR = bytes.fromhex("0011223344556677889900112233445566778899")
-KEY_ID = 1
-ALGO_ID = 1
-BIP32_PATH = "m/44'/60'/0'/0/0"
-NONCE = 21
-GAS_PRICE = 13
-GAS_LIMIT = 21000
-AMOUNT = 1.22
-
-
-@pytest.fixture(name="verbose", params=[False, True])
-def verbose_fixture(request) -> bool:
-    return request.param
-
-
-def common(firmware: Firmware, app_client: EthAppClient) -> int:
-
-    if firmware == Firmware.NANOS:
-        pytest.skip("Not supported on LNS")
-    challenge = app_client.get_challenge()
-    return ResponseParser.challenge(challenge.data)
-
-
-def test_send_fund(firmware: Firmware,
-                   backend: BackendInterface,
-                   navigator: Navigator,
-                   scenario_navigator: NavigateWithScenario,
-                   verbose: bool):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    if verbose:
-        settings_toggle(firmware, navigator, [SettingID.VERBOSE_ENS])
-
-    app_client.provide_domain_name(challenge, NAME, ADDR)
-
-    with app_client.sign(BIP32_PATH,
-                         {
-                             "nonce": NONCE,
-                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
-                             "gas": GAS_LIMIT,
-                             "to": ADDR,
-                             "value": Web3.to_wei(AMOUNT, "ether"),
-                             "chainId": CHAIN_ID
-                         }):
-        if firmware.is_nano:
-            end_text = "Accept"
-        else:
-            end_text = "Sign"
-
-        scenario_navigator.review_approve(test_name=f"domain_name_verbose_{str(verbose)}", custom_screen_text=end_text)
-
-
-def test_send_fund_wrong_challenge(firmware: Firmware, backend: BackendInterface):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    with pytest.raises(ExceptionRAPDU) as e:
-        app_client.provide_domain_name(~challenge & 0xffffffff, NAME, ADDR)
-    assert e.value.status == StatusWord.INVALID_DATA
-
-
-def test_send_fund_wrong_addr(firmware: Firmware,
-                              backend: BackendInterface,
-                              scenario_navigator: NavigateWithScenario):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    app_client.provide_domain_name(challenge, NAME, ADDR)
-
-    addr = bytearray(ADDR)
-    addr.reverse()
-
-    with app_client.sign(BIP32_PATH,
-                         {
-                             "nonce": NONCE,
-                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
-                             "gas": GAS_LIMIT,
-                             "to": bytes(addr),
-                             "value": Web3.to_wei(AMOUNT, "ether"),
-                             "chainId": CHAIN_ID
-                         }):
-        if firmware.is_nano:
-            end_text = "Accept"
-        else:
-            end_text = "Sign"
-
-        scenario_navigator.review_approve(test_name="domain_name_wrong_addr", custom_screen_text=end_text)
-
-
-def test_send_fund_non_mainnet(firmware: Firmware,
-                               backend: BackendInterface,
-                               scenario_navigator: NavigateWithScenario):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    app_client.provide_domain_name(challenge, NAME, ADDR)
-
-    with app_client.sign(BIP32_PATH,
-                         {
-                             "nonce": NONCE,
-                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
-                             "gas": GAS_LIMIT,
-                             "to": ADDR,
-                             "value": Web3.to_wei(AMOUNT, "ether"),
-                             "chainId": 5
-                         }):
-        if firmware.is_nano:
-            end_text = "Accept"
-        else:
-            end_text = "Sign"
-
-        scenario_navigator.review_approve(test_name="domain_name_non_mainnet", custom_screen_text=end_text)
-
-
-def test_send_fund_unknown_chain(firmware: Firmware,
-                                 backend: BackendInterface,
-                                 scenario_navigator: NavigateWithScenario):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    app_client.provide_domain_name(challenge, NAME, ADDR)
-
-    with app_client.sign(BIP32_PATH,
-                         {
-                             "nonce": NONCE,
-                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
-                             "gas": GAS_LIMIT,
-                             "to": ADDR,
-                             "value": Web3.to_wei(AMOUNT, "ether"),
-                             "chainId": 9
-                         }):
-        if firmware.is_nano:
-            end_text = "Accept"
-        else:
-            end_text = "Sign"
-
-        scenario_navigator.review_approve(test_name="domain_name_unknown_chain", custom_screen_text=end_text)
-
-
-def test_send_fund_domain_too_long(firmware: Firmware, backend: BackendInterface):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    with pytest.raises(ExceptionRAPDU) as e:
-        app_client.provide_domain_name(challenge, "ledger" + "0"*25 + ".eth", ADDR)
-    assert e.value.status == StatusWord.INVALID_DATA
-
-
-def test_send_fund_domain_invalid_character(firmware: Firmware, backend: BackendInterface):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    with pytest.raises(ExceptionRAPDU) as e:
-        app_client.provide_domain_name(challenge, "l\xe8dger.eth", ADDR)
-    assert e.value.status == StatusWord.INVALID_DATA
-
-
-def test_send_fund_uppercase(firmware: Firmware, backend: BackendInterface):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    with pytest.raises(ExceptionRAPDU) as e:
-        app_client.provide_domain_name(challenge, NAME.upper(), ADDR)
-    assert e.value.status == StatusWord.INVALID_DATA
-
-
-def test_send_fund_domain_non_ens(firmware: Firmware, backend: BackendInterface):
-    app_client = EthAppClient(backend)
-    challenge = common(firmware, app_client)
-
-    with pytest.raises(ExceptionRAPDU) as e:
-        app_client.provide_domain_name(challenge, "ledger.hte", ADDR)
-    assert e.value.status == StatusWord.INVALID_DATA
diff --git a/tests/ragger/test_eip712.py b/tests/ragger/test_eip712.py
index 1f64fb159..7713883de 100644
--- a/tests/ragger/test_eip712.py
+++ b/tests/ragger/test_eip712.py
@@ -11,28 +11,22 @@
 
 from ragger.backend import BackendInterface
 from ragger.firmware import Firmware
-from ragger.navigator import Navigator, NavInsID
-from ragger.navigator.navigation_scenario import NavigateWithScenario
+from ragger.navigator import Navigator, NavInsID, NavIns
+from ragger.error import ExceptionRAPDU
 
 import client.response_parser as ResponseParser
 from client.utils import recover_message
-from client.client import EthAppClient
+from client.client import EthAppClient, StatusWord, TrustedNameType, TrustedNameSource
 from client.eip712 import InputData
 from client.settings import SettingID, settings_toggle
 
 
-class SnapshotsConfig:
-    test_name: str
-    idx: int
-
-    def __init__(self, test_name: str, idx: int = 0):
-        self.test_name = test_name
-        self.idx = idx
-
-
 BIP32_PATH = "m/44'/60'/0'/0/0"
-SNAPS_CONFIG: Optional[SnapshotsConfig] = None
+autonext_idx: int
+snapshots_dirname: Optional[str] = None
 WALLET_ADDR: Optional[bytes] = None
+unfiltered_flow: bool = False
+skip_flow: bool = False
 
 
 def eip712_json_path() -> str:
@@ -73,14 +67,27 @@ def get_wallet_addr(client: EthAppClient) -> bytes:
     return WALLET_ADDR
 
 
-def test_eip712_legacy(backend: BackendInterface, scenario_navigator: NavigateWithScenario):
+def test_eip712_v0(firmware: Firmware, backend: BackendInterface, navigator: Navigator):
     app_client = EthAppClient(backend)
 
+    settings_toggle(firmware, navigator, [SettingID.BLIND_SIGNING])
     with open(input_files()[0], encoding="utf-8") as file:
         data = json.load(file)
     smsg = encode_typed_data(full_message=data)
     with app_client.eip712_sign_legacy(BIP32_PATH, smsg.header, smsg.body):
-        scenario_navigator.review_approve(custom_screen_text="Sign", do_comparison=False)
+        moves = []
+        if firmware.is_nano:
+            moves += [NavInsID.RIGHT_CLICK] * 2
+            if firmware == Firmware.NANOS:
+                moves += [NavInsID.RIGHT_CLICK] * 8
+            else:
+                moves += [NavInsID.RIGHT_CLICK] * 4
+            moves += [NavInsID.BOTH_CLICK]
+        else:
+            moves += [NavInsID.USE_CASE_CHOICE_REJECT]
+            moves += [NavInsID.SWIPE_CENTER_TO_LEFT] * 2
+            moves += [NavInsID.USE_CASE_REVIEW_CONFIRM]
+        navigator.navigate(moves)
 
     vrs = ResponseParser.signature(app_client.response().data)
     recovered_addr = recover_message(data, vrs)
@@ -89,23 +96,40 @@ def test_eip712_legacy(backend: BackendInterface, scenario_navigator: NavigateWi
 
 
 def autonext(firmware: Firmware, navigator: Navigator, default_screenshot_path: Path):
+    global autonext_idx
+
     moves = []
     if firmware.is_nano:
         moves = [NavInsID.RIGHT_CLICK]
     else:
-        moves = [NavInsID.SWIPE_CENTER_TO_LEFT]
-    if SNAPS_CONFIG is not None:
+        if autonext_idx == 0 and unfiltered_flow:
+            moves = [NavInsID.USE_CASE_CHOICE_REJECT]
+        else:
+            if autonext_idx == 2 and skip_flow:
+                InputData.disable_autonext()  # so the timer stops firing
+                if firmware == Firmware.STAX:
+                    skip_btn_pos = (355, 44)
+                else:  # FLEX
+                    skip_btn_pos = (420, 49)
+                moves = [
+                    # Ragger does not handle the skip button
+                    NavIns(NavInsID.TOUCH, skip_btn_pos),
+                    NavInsID.USE_CASE_CHOICE_CONFIRM,
+                ]
+            else:
+                moves = [NavInsID.SWIPE_CENTER_TO_LEFT]
+    if snapshots_dirname is not None:
         navigator.navigate_and_compare(default_screenshot_path,
-                                       SNAPS_CONFIG.test_name,
+                                       snapshots_dirname,
                                        moves,
                                        screen_change_before_first_instruction=False,
                                        screen_change_after_last_instruction=False,
-                                       snap_start_idx=SNAPS_CONFIG.idx)
-        SNAPS_CONFIG.idx += 1
+                                       snap_start_idx=autonext_idx)
     else:
         navigator.navigate(moves,
                            screen_change_before_first_instruction=False,
                            screen_change_after_last_instruction=False)
+    autonext_idx += len(moves)
 
 
 def eip712_new_common(firmware: Firmware,
@@ -116,6 +140,12 @@ def eip712_new_common(firmware: Firmware,
                       filters: Optional[dict],
                       verbose: bool,
                       golden_run: bool):
+    global autonext_idx
+    global unfiltered_flow
+    global skip_flow
+    global snapshots_dirname
+
+    autonext_idx = 0
     assert InputData.process_data(app_client,
                                   json_data,
                                   filters,
@@ -129,25 +159,31 @@ def eip712_new_common(firmware: Firmware,
                 moves += [NavInsID.RIGHT_CLICK] * 2
             moves += [NavInsID.BOTH_CLICK]
         else:
-            # this move is necessary most of the times, but can't be 100% sure with the fields grouping
-            moves += [NavInsID.SWIPE_CENTER_TO_LEFT]
-            # need to skip the message hash
-            if not verbose and filters is None:
+            if not skip_flow:
+                # this move is necessary most of the times, but can't be 100% sure with the fields grouping
                 moves += [NavInsID.SWIPE_CENTER_TO_LEFT]
+                # need to skip the message hash
+                if not verbose and filters is None:
+                    moves += [NavInsID.SWIPE_CENTER_TO_LEFT]
             moves += [NavInsID.USE_CASE_REVIEW_CONFIRM]
-        if SNAPS_CONFIG is not None:
+        if snapshots_dirname is not None:
             # Could break (time-out) if given a JSON that requires less moves
             # TODO: Maybe take list of moves as input instead of trying to guess them ?
             navigator.navigate_and_compare(default_screenshot_path,
-                                           SNAPS_CONFIG.test_name,
+                                           snapshots_dirname,
                                            moves,
-                                           snap_start_idx=SNAPS_CONFIG.idx)
+                                           snap_start_idx=autonext_idx)
         else:
             # Do them one-by-one to prevent an unnecessary move from timing-out and failing the test
             for move in moves:
                 navigator.navigate([move],
                                    screen_change_before_first_instruction=False,
                                    screen_change_after_last_instruction=False)
+    # reset values
+    unfiltered_flow = False
+    skip_flow = False
+    snapshots_dirname = None
+
     return ResponseParser.signature(app_client.response().data)
 
 
@@ -158,6 +194,9 @@ def test_eip712_new(firmware: Firmware,
                     input_file: Path,
                     verbose: bool,
                     filtering: bool):
+    global unfiltered_flow
+
+    settings_to_toggle: list[SettingID] = []
     app_client = EthAppClient(backend)
     if firmware == Firmware.NANOS:
         pytest.skip("Not supported on LNS")
@@ -172,9 +211,17 @@ def test_eip712_new(firmware: Firmware,
                 filters = json.load(f)
         except (IOError, json.decoder.JSONDecodeError) as e:
             pytest.skip(f"{filterfile.name}: {e.strerror}")
+    else:
+        settings_to_toggle.append(SettingID.BLIND_SIGNING)
 
     if verbose:
-        settings_toggle(firmware, navigator, [SettingID.VERBOSE_EIP712])
+        settings_to_toggle.append(SettingID.VERBOSE_EIP712)
+
+    if not filters or verbose:
+        unfiltered_flow = True
+
+    if len(settings_to_toggle) > 0:
+        settings_toggle(firmware, navigator, settings_to_toggle)
 
     with open(input_file, encoding="utf-8") as file:
         data = json.load(file)
@@ -242,14 +289,14 @@ def __init__(self, data: dict, filters: dict, suffix: str = ""):
             "name": "Advanced Filtering",
             "tokens": [
                 {
-                    "addr": "0x6b175474e89094c44da98b954eedeac495271d0f",
-                    "ticker": "DAI",
+                    "addr": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
+                    "ticker": "WETH",
                     "decimals": 18,
                     "chain_id": 1,
                 },
                 {
-                    "addr": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
-                    "ticker": "WETH",
+                    "addr": "0x6b175474e89094c44da98b954eedeac495271d0f",
+                    "ticker": "DAI",
                     "decimals": 18,
                     "chain_id": 1,
                 },
@@ -258,20 +305,20 @@ def __init__(self, data: dict, filters: dict, suffix: str = ""):
                 "value_send": {
                     "type": "amount_join_value",
                     "name": "Send",
-                    "token": 0,
+                    "token": 1,
                 },
                 "token_send": {
                     "type": "amount_join_token",
-                    "token": 0,
+                    "token": 1,
                 },
                 "value_recv": {
                     "type": "amount_join_value",
                     "name": "Receive",
-                    "token": 1,
+                    "token": 0,
                 },
                 "token_recv": {
                     "type": "amount_join_token",
-                    "token": 1,
+                    "token": 0,
                 },
                 "with": {
                     "type": "raw",
@@ -417,13 +464,13 @@ def test_eip712_advanced_filtering(firmware: Firmware,
                                    test_name: str,
                                    data_set: DataSet,
                                    golden_run: bool):
-    global SNAPS_CONFIG
+    global snapshots_dirname
 
     app_client = EthAppClient(backend)
     if firmware == Firmware.NANOS:
         pytest.skip("Not supported on LNS")
 
-    SNAPS_CONFIG = SnapshotsConfig(test_name + data_set.suffix)
+    snapshots_dirname = test_name + data_set.suffix
 
     vrs = eip712_new_common(firmware,
                             navigator,
@@ -437,3 +484,367 @@ def test_eip712_advanced_filtering(firmware: Firmware,
     # verify signature
     addr = recover_message(data_set.data, vrs)
     assert addr == get_wallet_addr(app_client)
+
+
+def test_eip712_filtering_empty_array(firmware: Firmware,
+                                      backend: BackendInterface,
+                                      navigator: Navigator,
+                                      default_screenshot_path: Path,
+                                      test_name: str,
+                                      golden_run: bool):
+    global snapshots_dirname
+
+    app_client = EthAppClient(backend)
+    if firmware == Firmware.NANOS:
+        pytest.skip("Not supported on LNS")
+
+    snapshots_dirname = test_name
+
+    data = {
+        "types": {
+            "EIP712Domain": [
+                {"name": "name", "type": "string"},
+                {"name": "version", "type": "string"},
+                {"name": "chainId", "type": "uint256"},
+                {"name": "verifyingContract", "type": "address"},
+            ],
+            "Person": [
+                {"name": "name", "type": "string"},
+                {"name": "addr", "type": "address"},
+            ],
+            "Message": [
+                {"name": "title", "type": "string"},
+                {"name": "to", "type": "Person[]"},
+            ],
+            "Root": [
+                {"name": "text", "type": "string"},
+                {"name": "subtext", "type": "string[]"},
+                {"name": "msg_list1", "type": "Message[]"},
+                {"name": "msg_list2", "type": "Message[]"},
+            ],
+        },
+        "primaryType": "Root",
+        "domain": {
+            "name": "test",
+            "version": "1",
+            "verifyingContract": "0x0000000000000000000000000000000000000000",
+            "chainId": 1,
+        },
+        "message": {
+            "text": "This is a test",
+            "subtext": [],
+            "msg_list1": [
+                {
+                    "title": "This is a test",
+                    "to": [],
+                }
+            ],
+            "msg_list2": [],
+        }
+    }
+    filters = {
+        "name": "Empty array filtering",
+        "fields": {
+            "text": {
+                "type": "raw",
+                "name": "Text",
+            },
+            "subtext.[]": {
+                "type": "raw",
+                "name": "Sub-Text",
+            },
+            "msg_list1.[].to.[].addr": {
+                "type": "raw",
+                "name": "(1) Recipient addr",
+            },
+            "msg_list2.[].to.[].addr": {
+                "type": "raw",
+                "name": "(2) Recipient addr",
+            },
+        }
+    }
+    vrs = eip712_new_common(firmware,
+                            navigator,
+                            default_screenshot_path,
+                            app_client,
+                            data,
+                            filters,
+                            False,
+                            golden_run)
+
+    # verify signature
+    addr = recover_message(data, vrs)
+    assert addr == get_wallet_addr(app_client)
+
+
+TOKENS = [
+    [
+        {
+            "addr": "0x1111111111111111111111111111111111111111",
+            "ticker": "SRC",
+            "decimals": 18,
+            "chain_id": 1,
+        },
+        {},
+    ],
+    [
+        {},
+        {
+            "addr": "0x2222222222222222222222222222222222222222",
+            "ticker": "DST",
+            "decimals": 18,
+            "chain_id": 1,
+        },
+    ]
+]
+
+
+@pytest.fixture(name="tokens", params=TOKENS)
+def tokens_fixture(request) -> list[dict]:
+    return request.param
+
+
+def test_eip712_advanced_missing_token(firmware: Firmware,
+                                       backend: BackendInterface,
+                                       navigator: Navigator,
+                                       default_screenshot_path: Path,
+                                       test_name: str,
+                                       tokens: list[dict],
+                                       golden_run: bool):
+    global snapshots_dirname
+
+    test_name += "-%s-%s" % (len(tokens[0]) == 0, len(tokens[1]) == 0)
+    snapshots_dirname = test_name
+
+    app_client = EthAppClient(backend)
+    if firmware == Firmware.NANOS:
+        pytest.skip("Not supported on LNS")
+
+    data = {
+        "types": {
+            "EIP712Domain": [
+                {"name": "name", "type": "string"},
+                {"name": "version", "type": "string"},
+                {"name": "chainId", "type": "uint256"},
+                {"name": "verifyingContract", "type": "address"},
+            ],
+            "Root": [
+                {"name": "token_from", "type": "address"},
+                {"name": "value_from", "type": "uint256"},
+                {"name": "token_to", "type": "address"},
+                {"name": "value_to", "type": "uint256"},
+            ]
+        },
+        "primaryType": "Root",
+        "domain": {
+            "name": "test",
+            "version": "1",
+            "verifyingContract": "0x0000000000000000000000000000000000000000",
+            "chainId": 1,
+        },
+        "message": {
+            "token_from": "0x1111111111111111111111111111111111111111",
+            "value_from": web3.Web3.to_wei(3.65, "ether"),
+            "token_to": "0x2222222222222222222222222222222222222222",
+            "value_to": web3.Web3.to_wei(15.47, "ether"),
+        }
+    }
+
+    filters = {
+        "name": "Token not in CAL test",
+        "tokens": tokens,
+        "fields": {
+            "token_from": {
+                "type": "amount_join_token",
+                "token": 0,
+            },
+            "value_from": {
+                "type": "amount_join_value",
+                "name": "From",
+                "token": 0,
+            },
+            "token_to": {
+                "type": "amount_join_token",
+                "token": 1,
+            },
+            "value_to": {
+                "type": "amount_join_value",
+                "name": "To",
+                "token": 1,
+            },
+        }
+    }
+    vrs = eip712_new_common(firmware,
+                            navigator,
+                            default_screenshot_path,
+                            app_client,
+                            data,
+                            filters,
+                            False,
+                            golden_run)
+
+    # verify signature
+    addr = recover_message(data, vrs)
+    assert addr == get_wallet_addr(app_client)
+
+
+TRUSTED_NAMES = [
+    (TrustedNameType.CONTRACT, TrustedNameSource.CAL, "Validator contract"),
+    (TrustedNameType.ACCOUNT, TrustedNameSource.ENS, "validator.eth"),
+]
+
+FILT_TN_TYPES = [
+    [TrustedNameType.CONTRACT],
+    [TrustedNameType.ACCOUNT],
+    [TrustedNameType.CONTRACT, TrustedNameType.ACCOUNT],
+    [TrustedNameType.ACCOUNT, TrustedNameType.CONTRACT],
+]
+
+
+@pytest.fixture(name="trusted_name", params=TRUSTED_NAMES)
+def trusted_name_fixture(request) -> tuple:
+    return request.param
+
+
+@pytest.fixture(name="filt_tn_types", params=FILT_TN_TYPES)
+def filt_tn_types_fixture(request) -> list[TrustedNameType]:
+    return request.param
+
+
+def test_eip712_advanced_trusted_name(firmware: Firmware,
+                                      backend: BackendInterface,
+                                      navigator: Navigator,
+                                      default_screenshot_path: Path,
+                                      test_name: str,
+                                      trusted_name: tuple,
+                                      filt_tn_types: list[TrustedNameType],
+                                      golden_run: bool):
+    global snapshots_dirname
+
+    test_name += "_%s_with" % (str(trusted_name[0]).split(".")[-1].lower())
+    for t in filt_tn_types:
+        test_name += "_%s" % (str(t).split(".")[-1].lower())
+    snapshots_dirname = test_name
+
+    app_client = EthAppClient(backend)
+    if firmware == Firmware.NANOS:
+        pytest.skip("Not supported on LNS")
+
+    data = {
+        "types": {
+            "EIP712Domain": [
+                {"name": "name", "type": "string"},
+                {"name": "version", "type": "string"},
+                {"name": "chainId", "type": "uint256"},
+                {"name": "verifyingContract", "type": "address"},
+            ],
+            "Root": [
+                {"name": "validator", "type": "address"},
+                {"name": "enable", "type": "bool"},
+            ]
+        },
+        "primaryType": "Root",
+        "domain": {
+            "name": "test",
+            "version": "1",
+            "verifyingContract": "0x0000000000000000000000000000000000000000",
+            "chainId": 1,
+        },
+        "message": {
+            "validator": "0x1111111111111111111111111111111111111111",
+            "enable": True,
+        }
+    }
+
+    filters = {
+        "name": "Trusted name test",
+        "fields": {
+            "validator": {
+                "type": "trusted_name",
+                "name": "Validator",
+                "tn_type": filt_tn_types,
+                "tn_source": [TrustedNameSource.CAL],
+            },
+            "enable": {
+                "type": "raw",
+                "name": "State",
+            },
+        }
+    }
+
+    if trusted_name[0] is TrustedNameType.ACCOUNT:
+        challenge = ResponseParser.challenge(app_client.get_challenge().data)
+    else:
+        challenge = None
+
+    app_client.provide_trusted_name_v2(bytes.fromhex(data["message"]["validator"][2:]),
+                                       trusted_name[2],
+                                       trusted_name[0],
+                                       trusted_name[1],
+                                       data["domain"]["chainId"],
+                                       challenge=challenge)
+    vrs = eip712_new_common(firmware,
+                            navigator,
+                            default_screenshot_path,
+                            app_client,
+                            data,
+                            filters,
+                            False,
+                            golden_run)
+
+    # verify signature
+    addr = recover_message(data, vrs)
+    assert addr == get_wallet_addr(app_client)
+
+
+def test_eip712_bs_not_activated_error(firmware: Firmware,
+                                       backend: BackendInterface,
+                                       navigator: Navigator,
+                                       default_screenshot_path: Path):
+    app_client = EthAppClient(backend)
+    if firmware == Firmware.NANOS:
+        pytest.skip("Not supported on LNS")
+
+    with pytest.raises(ExceptionRAPDU) as e:
+        eip712_new_common(firmware,
+                          navigator,
+                          default_screenshot_path,
+                          app_client,
+                          ADVANCED_DATA_SETS[0].data,
+                          None,
+                          False,
+                          False)
+    InputData.disable_autonext()  # so the timer stops firing
+    assert e.value.status == StatusWord.INVALID_DATA
+
+
+def test_eip712_skip(firmware: Firmware,
+                     backend: BackendInterface,
+                     navigator: Navigator,
+                     default_screenshot_path: Path,
+                     test_name: str,
+                     golden_run: bool):
+    global unfiltered_flow
+    global skip_flow
+
+    app_client = EthAppClient(backend)
+    if firmware.is_nano:
+        pytest.skip("Not supported on Nano devices")
+
+    unfiltered_flow = True
+    skip_flow = True
+    settings_toggle(firmware, navigator, [SettingID.BLIND_SIGNING])
+    with open(input_files()[0], encoding="utf-8") as file:
+        data = json.load(file)
+    vrs = eip712_new_common(firmware,
+                            navigator,
+                            default_screenshot_path,
+                            app_client,
+                            data,
+                            None,
+                            False,
+                            golden_run)
+
+    # verify signature
+    addr = recover_message(data, vrs)
+    assert addr == get_wallet_addr(app_client)
diff --git a/tests/ragger/test_erc20information.py b/tests/ragger/test_erc20information.py
index a858f5574..dfe606634 100644
--- a/tests/ragger/test_erc20information.py
+++ b/tests/ragger/test_erc20information.py
@@ -5,7 +5,6 @@
 
 from client.client import EthAppClient, StatusWord
 
-
 def test_provide_erc20_token(backend: BackendInterface):
 
     app_client = EthAppClient(backend)
@@ -21,7 +20,7 @@ def test_provide_erc20_token_error(backend: BackendInterface):
 
     addr = bytes.fromhex("e41d2489571d322189246dafa5ebde1f4699f498")
     sign = bytes.fromhex("deadbeef")
-    with pytest.raises(ExceptionRAPDU) as e:
+    with pytest.raises(ExceptionRAPDU) as err:
         app_client.provide_token_metadata("ZRX", addr, 18, 1, sign)
 
-    assert e.value.status == StatusWord.INVALID_DATA
+    assert err.value.status == StatusWord.INVALID_DATA
diff --git a/tests/ragger/test_nft.py b/tests/ragger/test_nft.py
index 38ffa629c..ed3b08ff1 100644
--- a/tests/ragger/test_nft.py
+++ b/tests/ragger/test_nft.py
@@ -65,11 +65,12 @@ def common_test_nft(firmware: Firmware,
             pass
         _, DEVICE_ADDR, _ = ResponseParser.pk_addr(app_client.response().data)
 
-    data = collec.contract.encodeABI(action.fn_name, action.fn_args)
+    data = collec.contract.encode_abi(action.fn_name, action.fn_args)
     app_client.set_plugin(plugin_name,
                           collec.addr,
                           get_selector_from_data(data),
                           collec.chain_id)
+
     app_client.provide_nft_metadata(collec.name, collec.addr, collec.chain_id)
     tx_params = {
         "nonce": NONCE,
diff --git a/tests/ragger/test_trusted_name.py b/tests/ragger/test_trusted_name.py
new file mode 100644
index 000000000..5f7468a19
--- /dev/null
+++ b/tests/ragger/test_trusted_name.py
@@ -0,0 +1,290 @@
+from typing import Optional
+import pytest
+from web3 import Web3
+
+from ragger.backend import BackendInterface
+from ragger.firmware import Firmware
+from ragger.error import ExceptionRAPDU
+from ragger.navigator import Navigator
+from ragger.navigator.navigation_scenario import NavigateWithScenario
+
+import client.response_parser as ResponseParser
+from client.client import EthAppClient, StatusWord, TrustedNameType, TrustedNameSource
+from client.settings import SettingID, settings_toggle
+
+
+# Values used across all tests
+CHAIN_ID = 1
+NAME = "ledger.eth"
+ADDR = bytes.fromhex("0011223344556677889900112233445566778899")
+KEY_ID = 1
+ALGO_ID = 1
+BIP32_PATH = "m/44'/60'/0'/0/0"
+NONCE = 21
+GAS_PRICE = 13
+GAS_LIMIT = 21000
+AMOUNT = 1.22
+
+
+@pytest.fixture(name="verbose", params=[False, True])
+def verbose_fixture(request) -> bool:
+    return request.param
+
+
+def common(firmware: Firmware, app_client: EthAppClient, get_challenge: bool = True) -> Optional[int]:
+
+    if firmware == Firmware.NANOS:
+        pytest.skip("Not supported on LNS")
+
+    if get_challenge:
+        challenge = app_client.get_challenge()
+        return ResponseParser.challenge(challenge.data)
+    return None
+
+
+def test_trusted_name_v1(firmware: Firmware,
+                         backend: BackendInterface,
+                         navigator: Navigator,
+                         scenario_navigator: NavigateWithScenario,
+                         verbose: bool,
+                         test_name: str):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    if verbose:
+        settings_toggle(firmware, navigator, [SettingID.VERBOSE_ENS])
+        test_name += "_verbose"
+
+    app_client.provide_trusted_name_v1(ADDR, NAME, challenge)
+
+    with app_client.sign(BIP32_PATH,
+                         {
+                             "nonce": NONCE,
+                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
+                             "gas": GAS_LIMIT,
+                             "to": ADDR,
+                             "value": Web3.to_wei(AMOUNT, "ether"),
+                             "chainId": CHAIN_ID
+                         }):
+        if firmware.is_nano:
+            end_text = "Accept"
+        else:
+            end_text = "Sign"
+
+        scenario_navigator.review_approve(test_name=test_name, custom_screen_text=end_text)
+
+
+def test_trusted_name_v1_wrong_challenge(firmware: Firmware, backend: BackendInterface):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    with pytest.raises(ExceptionRAPDU) as e:
+        app_client.provide_trusted_name_v1(ADDR, NAME, ~challenge & 0xffffffff)
+    assert e.value.status == StatusWord.INVALID_DATA
+
+
+def test_trusted_name_v1_wrong_addr(firmware: Firmware,
+                                    backend: BackendInterface,
+                                    scenario_navigator: NavigateWithScenario,
+                                    test_name: str):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    app_client.provide_trusted_name_v1(ADDR, NAME, challenge)
+
+    addr = bytearray(ADDR)
+    addr.reverse()
+
+    with app_client.sign(BIP32_PATH,
+                         {
+                             "nonce": NONCE,
+                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
+                             "gas": GAS_LIMIT,
+                             "to": bytes(addr),
+                             "value": Web3.to_wei(AMOUNT, "ether"),
+                             "chainId": CHAIN_ID
+                         }):
+        if firmware.is_nano:
+            end_text = "Accept"
+        else:
+            end_text = "Sign"
+
+        scenario_navigator.review_approve(test_name=test_name, custom_screen_text=end_text)
+
+
+def test_trusted_name_v1_non_mainnet(firmware: Firmware,
+                                     backend: BackendInterface,
+                                     scenario_navigator: NavigateWithScenario,
+                                     test_name: str):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    app_client.provide_trusted_name_v1(ADDR, NAME, challenge)
+
+    with app_client.sign(BIP32_PATH,
+                         {
+                             "nonce": NONCE,
+                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
+                             "gas": GAS_LIMIT,
+                             "to": ADDR,
+                             "value": Web3.to_wei(AMOUNT, "ether"),
+                             "chainId": 5
+                         }):
+        if firmware.is_nano:
+            end_text = "Accept"
+        else:
+            end_text = "Sign"
+
+        scenario_navigator.review_approve(test_name=test_name, custom_screen_text=end_text)
+
+
+def test_trusted_name_v1_unknown_chain(firmware: Firmware,
+                                       backend: BackendInterface,
+                                       scenario_navigator: NavigateWithScenario,
+                                       test_name: str):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    app_client.provide_trusted_name_v1(ADDR, NAME, challenge)
+
+    with app_client.sign(BIP32_PATH,
+                         {
+                             "nonce": NONCE,
+                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
+                             "gas": GAS_LIMIT,
+                             "to": ADDR,
+                             "value": Web3.to_wei(AMOUNT, "ether"),
+                             "chainId": 9
+                         }):
+        if firmware.is_nano:
+            end_text = "Accept"
+        else:
+            end_text = "Sign"
+
+        scenario_navigator.review_approve(test_name=test_name, custom_screen_text=end_text)
+
+
+def test_trusted_name_v1_name_too_long(firmware: Firmware, backend: BackendInterface):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    with pytest.raises(ExceptionRAPDU) as e:
+        app_client.provide_trusted_name_v1(ADDR, "ledger" + "0"*25 + ".eth", challenge)
+    assert e.value.status == StatusWord.INVALID_DATA
+
+
+def test_trusted_name_v1_name_invalid_character(firmware: Firmware, backend: BackendInterface):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    with pytest.raises(ExceptionRAPDU) as e:
+        app_client.provide_trusted_name_v1(ADDR, "l\xe8dger.eth", challenge)
+    assert e.value.status == StatusWord.INVALID_DATA
+
+
+def test_trusted_name_v1_uppercase(firmware: Firmware, backend: BackendInterface):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    with pytest.raises(ExceptionRAPDU) as e:
+        app_client.provide_trusted_name_v1(ADDR, NAME.upper(), challenge)
+    assert e.value.status == StatusWord.INVALID_DATA
+
+
+def test_trusted_name_v1_name_non_ens(firmware: Firmware, backend: BackendInterface):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    with pytest.raises(ExceptionRAPDU) as e:
+        app_client.provide_trusted_name_v1(ADDR, "ledger.hte", challenge)
+    assert e.value.status == StatusWord.INVALID_DATA
+
+
+def test_trusted_name_v2(firmware: Firmware,
+                         backend: BackendInterface,
+                         scenario_navigator: NavigateWithScenario,
+                         test_name: str):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    app_client.provide_trusted_name_v2(ADDR,
+                                       NAME,
+                                       TrustedNameType.ACCOUNT,
+                                       TrustedNameSource.ENS,
+                                       CHAIN_ID,
+                                       challenge=challenge)
+
+    with app_client.sign(BIP32_PATH,
+                         {
+                             "nonce": NONCE,
+                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
+                             "gas": GAS_LIMIT,
+                             "to": ADDR,
+                             "value": Web3.to_wei(AMOUNT, "ether"),
+                             "chainId": CHAIN_ID
+                         }):
+        if firmware.is_nano:
+            end_text = "Accept"
+        else:
+            end_text = "Sign"
+
+        scenario_navigator.review_approve(test_name=test_name, custom_screen_text=end_text)
+
+
+def test_trusted_name_v2_wrong_chainid(firmware: Firmware,
+                                       backend: BackendInterface,
+                                       scenario_navigator: NavigateWithScenario,
+                                       test_name: str):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    app_client.provide_trusted_name_v2(ADDR,
+                                       NAME,
+                                       TrustedNameType.ACCOUNT,
+                                       TrustedNameSource.ENS,
+                                       CHAIN_ID,
+                                       challenge=challenge)
+
+    with app_client.sign(BIP32_PATH,
+                         {
+                             "nonce": NONCE,
+                             "gasPrice": Web3.to_wei(GAS_PRICE, "gwei"),
+                             "gas": GAS_LIMIT,
+                             "to": ADDR,
+                             "value": Web3.to_wei(AMOUNT, "ether"),
+                             "chainId": CHAIN_ID + 1,
+                         }):
+        if firmware.is_nano:
+            end_text = "Accept"
+        else:
+            end_text = "Sign"
+
+        scenario_navigator.review_approve(test_name=test_name, custom_screen_text=end_text)
+
+
+def test_trusted_name_v2_missing_challenge(firmware: Firmware, backend: BackendInterface):
+    app_client = EthAppClient(backend)
+    common(firmware, app_client, False)
+
+    with pytest.raises(ExceptionRAPDU) as e:
+        app_client.provide_trusted_name_v2(ADDR,
+                                           NAME,
+                                           TrustedNameType.ACCOUNT,
+                                           TrustedNameSource.ENS,
+                                           CHAIN_ID)
+    assert e.value.status == StatusWord.INVALID_DATA
+
+
+def test_trusted_name_v2_expired(firmware: Firmware, backend: BackendInterface):
+    app_client = EthAppClient(backend)
+    challenge = common(firmware, app_client)
+
+    with pytest.raises(ExceptionRAPDU) as e:
+        app_client.provide_trusted_name_v2(ADDR,
+                                           NAME,
+                                           TrustedNameType.ACCOUNT,
+                                           TrustedNameSource.ENS,
+                                           CHAIN_ID,
+                                           challenge=challenge,
+                                           not_valid_after=(0, 1, 2))
+    assert e.value.status == StatusWord.INVALID_DATA