feat(core): confirm ERC-8213 calldata digest if all data is shown
What changed, and why it matters
This commit adds a new user-facing safety feature for Trezor hardware wallets when signing Ethereum transactions. If the user chooses to view all the raw transaction data (calldata), the device will now also show a final cryptographic hash (digest) of that data, based on a community standard called ERC-8213. This helps users verify that what they saw on screen matches what is actually being signed, reducing the risk of hidden malicious changes in very long data fields. It is a defensive improvement, not a fix for an active bug or vulnerability.
No immediate action required; this is a defensive feature addition. Users benefit from verifying the displayed calldata digest against an independently computed ERC-8213 digest before approving large Ethereum transactions. Developers should complete the Bolt and Caesar implementations to avoid inconsistent security behavior across device models, and should review that the no-op stubs cannot be reached in a way that silently skips the digest on those layouts.
Security signals we found
Adds user-verifiable calldata digest display (ERC-8213) to mitigate tampering of long Ethereum transaction data
Hashes calldata with keccak256 seeded by total length, matching the ERC-8213 specification referenced in code comments
Adds a length-consistency check (confirmed_len == total_len) before displaying the digest
Bolt and Caesar layouts have no-op stub implementations, leaving the feature incomplete on those devices
Changes existing button label from 'Confirm all' to 'Skip and view hash', altering the user decision flow
Updates UI test fixtures, indicating new screens are rendered during signing
Evidence from the diff
The change implements ERC-8213 calldata digest confirmation for Ethereum transactions on T3T1/T3W1 devices. A new DataChunkConfirmer.hasher field computes a keccak256 digest over the full calldata, seeded with the total length as a 32-byte big-endian value. When the user opts to view all data chunks (confirm_blob_intro returns a skip flag), the hasher is initialized and each chunk is fed into it. After all chunks are processed, confirm_digest() is called, which verifies that the confirmed length equals the total length and then displays the resulting digest via a new confirm_calldata_digest UI flow. UI layouts for Delizia and Eckhart implement the digest screen; Bolt and Caesar currently have stub (no-op) implementations, marked with a TODO. New translation strings and a verb_view_all parameter for confirm_value_intro support the updated prompts.
Changed components
core/src/apps/ethereum/helpers.pycore/src/apps/ethereum/sign_tx.pycore/src/trezor/ui/layouts/delizia/__init__.pycore/src/trezor/ui/layouts/eckhart/__init__.pycore/src/trezor/ui/layouts/bolt/__init__.pycore/src/trezor/ui/layouts/caesar/__init__.pycore/embed/rust/src/ui/api/firmware_micropython.rscore/embed/rust/src/ui/layout_delizia/ui_firmware.rscore/embed/rust/src/ui/layout_eckhart/ui_firmware.rscore/embed/rust/src/ui/layout_bolt/ui_firmware.rscore/embed/rust/src/ui/layout_caesar/ui_firmware.rscore/embed/rust/src/ui/ui_firmware.rscore/translations/en.jsonInspect captured patch +194 / −32
diff --git a/core/.changelog.d/7315.added b/core/.changelog.d/7315.added
new file mode 100644
index 00000000..d4cde463
--- /dev/null
+++ b/core/.changelog.d/7315.added
@@ -0,0 +1 @@
+[T3T1,T3W1] Ethereum: Support calldata digest confirmation using ERC-8213.
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index 784be6b9..600d07dd 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -972,6 +972,7 @@ static void _librust_qstrs(void) {
MP_QSTR_verb;
MP_QSTR_verb_cancel;
MP_QSTR_verb_info;
+ MP_QSTR_verb_view_all;
MP_QSTR_verify;
MP_QSTR_version;
MP_QSTR_wait_ble_host_confirmation;
@@ -1318,6 +1319,7 @@ static void _librust_qstrs(void) {
MP_QSTR_ethereum__show_full_message;
MP_QSTR_ethereum__show_full_struct;
MP_QSTR_ethereum__sign_eip712;
+ MP_QSTR_ethereum__skip_to_hash;
MP_QSTR_ethereum__smart_info;
MP_QSTR_ethereum__staking_claim;
MP_QSTR_ethereum__staking_claim_address;
@@ -1349,6 +1351,7 @@ static void _librust_qstrs(void) {
MP_QSTR_ethereum__vault_redeem_intro;
MP_QSTR_ethereum__vault_redeem_to;
MP_QSTR_ethereum__vault_withdraw_intro;
+ MP_QSTR_ethereum__view_data_and_hash;
MP_QSTR_ethereum__withdraw;
MP_QSTR_ethereum__withdraw_amount;
MP_QSTR_ethereum__withdraw_from;
diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs
index fb1065b7..7dbe4a7b 100644
--- a/core/embed/rust/src/translations/generated/translated_string.rs
+++ b/core/embed/rust/src/translations/generated/translated_string.rs
@@ -1663,6 +1663,10 @@ pub enum TranslatedString {
words__authorization = 1259, // "Authorization"
words__comm_continue = 1260, // "Communication with your connected device failed. It's safe to continue."
words__function = 1261, // "Function"
+ #[cfg(feature = "universal_fw")]
+ ethereum__skip_to_hash = 1262, // "Skip and view hash"
+ #[cfg(feature = "universal_fw")]
+ ethereum__view_data_and_hash = 1263, // "View data and hash"
}
impl TranslatedString {
@@ -2932,6 +2936,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -4199,6 +4205,8 @@ impl TranslatedString {
18995,
19066,
19074,
+ 19092,
+ 19110,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -5465,6 +5473,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -6732,6 +6742,8 @@ impl TranslatedString {
18995,
19066,
19074,
+ 19092,
+ 19110,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -7998,6 +8010,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -9265,6 +9279,8 @@ impl TranslatedString {
18995,
19066,
19074,
+ 19092,
+ 19110,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -10531,6 +10547,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -11798,6 +11816,8 @@ impl TranslatedString {
18995,
19066,
19074,
+ 19092,
+ 19110,
];
} else if #[cfg(feature = "layout_caesar")] {
@@ -13065,6 +13085,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -14332,6 +14354,8 @@ impl TranslatedString {
16786,
16857,
16865,
+ 16883,
+ 16901,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -15598,6 +15622,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -16865,6 +16891,8 @@ impl TranslatedString {
16786,
16857,
16865,
+ 16883,
+ 16901,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -18131,6 +18159,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -19398,6 +19428,8 @@ impl TranslatedString {
16786,
16857,
16865,
+ 16883,
+ 16901,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -20664,6 +20696,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -21931,6 +21965,8 @@ impl TranslatedString {
16786,
16857,
16865,
+ 16883,
+ 16901,
];
} else if #[cfg(feature = "layout_delizia")] {
@@ -23198,6 +23234,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -24465,6 +24503,8 @@ impl TranslatedString {
18884,
18955,
18963,
+ 18981,
+ 18999,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -25731,6 +25771,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -26998,6 +27040,8 @@ impl TranslatedString {
18884,
18955,
18963,
+ 18981,
+ 18999,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -28264,6 +28308,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -29531,6 +29577,8 @@ impl TranslatedString {
18884,
18955,
18963,
+ 18981,
+ 18999,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -30797,6 +30845,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -32064,6 +32114,8 @@ impl TranslatedString {
18884,
18955,
18963,
+ 18981,
+ 18999,
];
} else if #[cfg(feature = "layout_eckhart")] {
@@ -33331,6 +33383,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -34598,6 +34652,8 @@ impl TranslatedString {
20271,
20342,
20350,
+ 20368,
+ 20386,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -35864,6 +35920,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -37131,6 +37189,8 @@ impl TranslatedString {
20271,
20342,
20350,
+ 20368,
+ 20386,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -38397,6 +38457,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -39664,6 +39726,8 @@ impl TranslatedString {
20271,
20342,
20350,
+ 20368,
+ 20386,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -40930,6 +40994,8 @@ impl TranslatedString {
"Authorization",
"Communication with your connected device failed. It's safe to continue.",
"Function",
+ "Skip and view hash",
+ "View data and hash",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -42197,6 +42263,8 @@ impl TranslatedString {
20271,
20342,
20350,
+ 20368,
+ 20386,
];
}
@@ -42787,6 +42855,8 @@ impl TranslatedString {
#[cfg(feature = "universal_fw")]
(Qstr::MP_QSTR_ethereum__sign_eip712, Self::ethereum__sign_eip712),
#[cfg(feature = "universal_fw")]
+ (Qstr::MP_QSTR_ethereum__skip_to_hash, Self::ethereum__skip_to_hash),
+ #[cfg(feature = "universal_fw")]
(Qstr::MP_QSTR_ethereum__smart_info, Self::ethereum__smart_info),
#[cfg(feature = "universal_fw")]
(Qstr::MP_QSTR_ethereum__staking_claim, Self::ethereum__staking_claim),
@@ -42849,6 +42919,8 @@ impl TranslatedString {
#[cfg(feature = "universal_fw")]
(Qstr::MP_QSTR_ethereum__vault_withdraw_intro, Self::ethereum__vault_withdraw_intro),
#[cfg(feature = "universal_fw")]
+ (Qstr::MP_QSTR_ethereum__view_data_and_hash, Self::ethereum__view_data_and_hash),
+ #[cfg(feature = "universal_fw")]
(Qstr::MP_QSTR_ethereum__withdraw, Self::ethereum__withdraw),
#[cfg(feature = "universal_fw")]
(Qstr::MP_QSTR_ethereum__withdraw_amount, Self::ethereum__withdraw_amount),
diff --git a/core/embed/rust/src/ui/api/firmware_micropython.rs b/core/embed/rust/src/ui/api/firmware_micropython.rs
index 6e0aa63e..a00c07f0 100644
--- a/core/embed/rust/src/ui/api/firmware_micropython.rs
+++ b/core/embed/rust/src/ui/api/firmware_micropython.rs
@@ -212,6 +212,10 @@ extern "C" fn new_confirm_value_intro(n_args: usize, args: *const Obj, kwargs: *
.get(Qstr::MP_QSTR_verb_cancel)
.unwrap_or_else(|_| Obj::const_none())
.try_into_option()?;
+ let verb_view_all: Option<TString> = kwargs
+ .get(Qstr::MP_QSTR_verb_view_all)
+ .unwrap_or_else(|_| Obj::const_none())
+ .try_into_option()?;
let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?;
let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?;
@@ -221,6 +225,7 @@ extern "C" fn new_confirm_value_intro(n_args: usize, args: *const Obj, kwargs: *
subtitle,
verb,
verb_cancel,
+ verb_view_all,
hold,
chunkify,
)?;
@@ -1574,6 +1579,7 @@ pub static mp_module_trezorui_api: Module = obj_module! {
/// verb_cancel: str | None = None,
/// hold: bool = False,
/// chunkify: bool = False,
+ /// verb_view_all: str | None = None,
/// ) -> LayoutContext[UiResult]:
/// """Similar to `confirm_value`, but only the first page is shown.
/// This function is intended as a building block for a higher level `confirm_blob`
diff --git a/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs b/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs
index 9e0a233d..6ef06917 100644
--- a/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_bolt/ui_firmware.rs
@@ -143,6 +143,7 @@ impl FirmwareUI for UIBolt {
_subtitle: Option<TString<'static>>,
_verb: Option<TString<'static>>,
_verb_cancel: Option<TString<'static>>,
+ _verb_view_all: Option<TString<'static>>,
_hold: bool,
_chunkify: bool,
) -> Result<Gc<LayoutObj>, Error> {
diff --git a/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs b/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs
index e89d1a06..144dbb4d 100644
--- a/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_caesar/ui_firmware.rs
@@ -190,6 +190,7 @@ impl FirmwareUI for UICaesar {
_subtitle: Option<TString<'static>>,
_verb: Option<TString<'static>>,
_verb_cancel: Option<TString<'static>>,
+ _verb_view_all: Option<TString<'static>>,
_hold: bool,
_chunkify: bool,
) -> Result<Gc<LayoutObj>, Error> {
diff --git a/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs b/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs
index d275ff15..ef5cf1d5 100644
--- a/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_delizia/ui_firmware.rs
@@ -156,6 +156,7 @@ impl FirmwareUI for UIDelizia {
subtitle: Option<TString<'static>>,
verb: Option<TString<'static>>,
verb_cancel: Option<TString<'static>>,
+ verb_view_all: Option<TString<'static>>,
hold: bool,
chunkify: bool,
) -> Result<Gc<LayoutObj>, Error> {
@@ -166,7 +167,9 @@ impl FirmwareUI for UIDelizia {
Some(TR::instructions__view_all_data.into()),
)
.with_verb(verb)
- .with_verb_info(Some(TR::buttons__view_all_data.into()))
+ .with_verb_info(Some(
+ verb_view_all.unwrap_or(TR::buttons__view_all_data.into()),
+ ))
.with_description_font(&theme::TEXT_SUB_GREEN_LIME)
.with_subtitle(subtitle)
.with_verb_cancel(verb_cancel)
diff --git a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
index e58497c7..de722a6f 100644
--- a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs
@@ -574,6 +574,7 @@ impl FirmwareUI for UIEckhart {
subtitle: Option<TString<'static>>,
verb: Option<TString<'static>>,
verb_cancel: Option<TString<'static>>,
+ verb_view_all: Option<TString<'static>>,
hold: bool,
chunkify: bool,
) -> Result<Gc<LayoutObj>, Error> {
@@ -581,7 +582,7 @@ impl FirmwareUI for UIEckhart {
title,
subtitle,
value,
- TR::buttons__view_all_data.into(),
+ verb_view_all.unwrap_or(TR::buttons__view_all_data.into()),
verb_cancel,
verb,
hold,
diff --git a/core/embed/rust/src/ui/ui_firmware.rs b/core/embed/rust/src/ui/ui_firmware.rs
index 8b7081ed..54268606 100644
--- a/core/embed/rust/src/ui/ui_firmware.rs
+++ b/core/embed/rust/src/ui/ui_firmware.rs
@@ -74,12 +74,14 @@ pub trait FirmwareUI {
external_menu: bool,
) -> Result<impl LayoutMaybeTrace, Error>;
+ #[allow(clippy::too_many_arguments)]
fn confirm_value_intro(
title: TString<'static>,
value: Obj, // TODO: replace Obj
subtitle: Option<TString<'static>>,
verb: Option<TString<'static>>,
verb_cancel: Option<TString<'static>>,
+ verb_view_all: Option<TString<'static>>,
hold: bool,
chunkify: bool,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi
index ef41b128..930e8135 100644
--- a/core/mocks/generated/trezorui_api.pyi
+++ b/core/mocks/generated/trezorui_api.pyi
@@ -216,6 +216,7 @@ def confirm_value_intro(
verb_cancel: str | None = None,
hold: bool = False,
chunkify: bool = False,
+ verb_view_all: str | None = None,
) -> LayoutContext[UiResult]:
"""Similar to `confirm_value`, but only the first page is shown.
This function is intended as a building block for a higher level `confirm_blob`
diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi
index a85ab9f8..0786c1b2 100644
--- a/core/mocks/trezortranslate_keys.pyi
+++ b/core/mocks/trezortranslate_keys.pyi
@@ -373,6 +373,7 @@ class TR:
ethereum__show_full_message: str = "Show full message"
ethereum__show_full_struct: str = "Show full struct"
ethereum__sign_eip712: str = "Really sign EIP-712 typed data?"
+ ethereum__skip_to_hash: str = "Skip and view hash"
ethereum__smart_info: str = "Smart account contract info"
ethereum__staking_claim: str = "Claim"
ethereum__staking_claim_address: str = "Claim address"
@@ -404,6 +405,7 @@ class TR:
ethereum__vault_redeem_intro: str = "Review details to redeem from vault."
ethereum__vault_redeem_to: str = "Redeem to"
ethereum__vault_withdraw_intro: str = "Review details to withdraw from vault."
+ ethereum__view_data_and_hash: str = "View data and hash"
ethereum__withdraw: str = "Withdraw"
ethereum__withdraw_amount: str = "Withdraw amount"
ethereum__withdraw_from: str = "Withdraw from"
diff --git a/core/src/apps/ethereum/helpers.py b/core/src/apps/ethereum/helpers.py
index e1bfd4e5..5ce2c271 100644
--- a/core/src/apps/ethereum/helpers.py
+++ b/core/src/apps/ethereum/helpers.py
@@ -237,6 +237,7 @@ class DataChunkConfirmer:
self.confirmed_len = 0
self.progress_bar = None
self.first: bool = True
+ self.hasher: HashWriter | None = None
async def confirm(self, chunk: AnyBytes) -> None:
from trezor.enums import ButtonRequestType
@@ -251,12 +252,20 @@ class DataChunkConfirmer:
subtitle=TR.ethereum__data_size_template.format(self.total_len),
verb=TR.buttons__confirm,
verb_cancel=TR.send__cancel_sign,
+ verb_view_all=TR.ethereum__view_data_and_hash,
br_name="confirm_data",
br_code=ButtonRequestType.SignTx,
)
if skip:
# skip following chunks confirmation - use a progress bar instead
self.progress_bar = self._get_progress_indicator()
+ else:
+ # ERC-8213 calldata digest will be confirmed after all calldata is hashed
+ # https://ethereum-magicians.org/t/erc-8213-wallet-signature-and-calldata-digest-display/24295#calldata-digest
+ self.hasher = keccak256(self.total_len.to_bytes(32, "big"))
+
+ if self.hasher is not None:
+ self.hasher.extend(chunk)
if self.progress_bar is not None:
return self.progress_bar(chunk)
@@ -301,6 +310,20 @@ class DataChunkConfirmer:
return confirm_fn
+ async def confirm_digest(self) -> None:
+ if self.hasher is None:
+ return
+
+ if self.confirmed_len != self.total_len:
+ from trezor.wire import ProcessError
+
+ raise ProcessError("Missing calldata")
+
+ from trezor.ui.layouts import confirm_calldata_digest
+
+ # TODO: missing on Bolt & Caesar
+ return await confirm_calldata_digest(self.hasher.get_digest(), self.total_len)
+
def keccak256(data: AnyBytes | None = None) -> HashWriter:
from trezor.crypto.hashlib import sha3_256
diff --git a/core/src/apps/ethereum/sign_tx.py b/core/src/apps/ethereum/sign_tx.py
index 78abed84..e0592331 100644
--- a/core/src/apps/ethereum/sign_tx.py
+++ b/core/src/apps/ethereum/sign_tx.py
@@ -308,6 +308,8 @@ async def _confirm_data_chunks(
await data_chunk_confirmer.confirm(chunk)
data_left -= len(chunk)
+ await data_chunk_confirmer.confirm_digest()
+
async def _get_next_chunk(data_left: int) -> AnyBytes:
from trezor.messages import EthereumTxAck
diff --git a/core/src/trezor/ui/layouts/bolt/__init__.py b/core/src/trezor/ui/layouts/bolt/__init__.py
index e47e3757..edda7208 100644
--- a/core/src/trezor/ui/layouts/bolt/__init__.py
+++ b/core/src/trezor/ui/layouts/bolt/__init__.py
@@ -727,6 +727,7 @@ async def confirm_blob_intro(
subtitle: str,
verb: str,
verb_cancel: str,
+ verb_view_all: str,
br_name: str,
br_code: ButtonRequestType = BR_CODE_OTHER,
) -> bool:
@@ -1081,6 +1082,9 @@ if not utils.BITCOIN_ONLY:
return len(prefix)
return None
+ async def confirm_calldata_digest(digest: AnyBytes, size: int) -> None:
+ pass
+
def confirm_ethereum_unknown_contract_warning(
_title: str | None,
) -> Awaitable[None]:
diff --git a/core/src/trezor/ui/layouts/caesar/__init__.py b/core/src/trezor/ui/layouts/caesar/__init__.py
index 477bbeb7..bcea757e 100644
--- a/core/src/trezor/ui/layouts/caesar/__init__.py
+++ b/core/src/trezor/ui/layouts/caesar/__init__.py
@@ -752,6 +752,7 @@ async def confirm_blob_intro(
subtitle: str,
verb: str,
verb_cancel: str,
+ verb_view_all: str,
br_name: str,
br_code: ButtonRequestType = BR_CODE_OTHER,
) -> bool:
@@ -1122,6 +1123,9 @@ if not utils.BITCOIN_ONLY:
return len(prefix)
return None
+ async def confirm_calldata_digest(digest: AnyBytes, size: int) -> None:
+ pass
+
def confirm_ethereum_unknown_contract_warning(
_title: str | None,
) -> Awaitable[None]:
diff --git a/core/src/trezor/ui/layouts/delizia/__init__.py b/core/src/trezor/ui/layouts/delizia/__init__.py
index 78b0a3ad..ecd621e3 100644
--- a/core/src/trezor/ui/layouts/delizia/__init__.py
+++ b/core/src/trezor/ui/layouts/delizia/__init__.py
@@ -674,6 +674,7 @@ async def confirm_blob_intro(
subtitle: str,
verb: str,
verb_cancel: str,
+ verb_view_all: str,
br_name: str,
br_code: ButtonRequestType = BR_CODE_OTHER,
) -> bool:
@@ -690,6 +691,7 @@ async def confirm_blob_intro(
subtitle=subtitle,
verb=verb,
verb_cancel=verb_cancel,
+ verb_view_all=verb_view_all,
) as layout:
res = await interact(
layout,
@@ -1032,7 +1034,7 @@ if not utils.BITCOIN_ONLY:
),
para=[(utils.hexlify_if_bytes(prefix), True)],
confirm="", # will return False
- button_text=TR.words__confirm_all, # will return True
+ button_text=TR.ethereum__skip_to_hash, # will return True
br_name=br_name,
br_code=br_code,
)
@@ -1040,6 +1042,17 @@ if not utils.BITCOIN_ONLY:
return len(prefix)
return None
+ async def confirm_calldata_digest(digest: AnyBytes, size: int) -> None:
+ await confirm_blob(
+ title=TR.ethereum__title_input_data,
+ subtitle=TR.ethereum__data_size_template.format(size),
+ description=TR.ethereum__calldata_digest,
+ data=digest,
+ prompt_screen=False,
+ br_name="confirm_digest",
+ br_code=ButtonRequestType.SignTx,
+ )
+
def _get_account_info_items(
account: str | None, account_path: str | None, title: str | None = None
) -> list[tuple[str, list[StrPropertyType], str | None]]:
diff --git a/core/src/trezor/ui/layouts/eckhart/__init__.py b/core/src/trezor/ui/layouts/eckhart/__init__.py
index 056bff00..d782930f 100644
--- a/core/src/trezor/ui/layouts/eckhart/__init__.py
+++ b/core/src/trezor/ui/layouts/eckhart/__init__.py
@@ -689,6 +689,7 @@ async def confirm_blob_intro(
subtitle: str,
verb: str,
verb_cancel: str,
+ verb_view_all: str,
br_name: str,
br_code: ButtonRequestType = BR_CODE_OTHER,
) -> bool:
@@ -705,6 +706,7 @@ async def confirm_blob_intro(
subtitle=subtitle,
verb=verb,
verb_cancel=verb_cancel,
+ verb_view_all=verb_view_all,
) as layout:
res = await interact(
layout,
@@ -1033,7 +1035,7 @@ if not utils.BITCOIN_ONLY:
title=TR.ethereum__title_input_data_bytes.format(confirmed_len, total_len),
para=[(utils.hexlify_if_bytes(prefix), True)],
confirm=verb, # will return False
- button_text=TR.words__confirm_all, # will return True
+ button_text=TR.ethereum__skip_to_hash, # will return True
br_name=br_name,
br_code=br_code,
)
@@ -1041,6 +1043,16 @@ if not utils.BITCOIN_ONLY:
return len(prefix)
return None
+ async def confirm_calldata_digest(digest: AnyBytes, size: int) -> None:
+ await confirm_blob(
+ title=TR.ethereum__title_input_data,
+ subtitle=TR.ethereum__data_size_template.format(size),
+ description=TR.ethereum__calldata_digest,
+ data=digest,
+ br_name="confirm_digest",
+ br_code=ButtonRequestType.SignTx,
+ )
+
def _get_account_info_items(
account: str | None, account_path: str | None
) -> list[StrPropertyType]:
diff --git a/core/translations/en.json b/core/translations/en.json
index ac8b5e7f..dba79890 100644
--- a/core/translations/en.json
+++ b/core/translations/en.json
@@ -870,6 +870,7 @@
"ethereum__show_full_message": "Show full message",
"ethereum__show_full_struct": "Show full struct",
"ethereum__sign_eip712": "Really sign EIP-712 typed data?",
+ "ethereum__skip_to_hash": "Skip and view hash",
"ethereum__smart_info": "Smart account contract info",
"ethereum__staking_claim": "Claim",
"ethereum__staking_claim_address": "Claim address",
@@ -926,6 +927,7 @@
"ethereum__vault_redeem_intro": "Review details to redeem from vault.",
"ethereum__vault_redeem_to": "Redeem to",
"ethereum__vault_withdraw_intro": "Review details to withdraw from vault.",
+ "ethereum__view_data_and_hash": "View data and hash",
"ethereum__withdraw": "Withdraw",
"ethereum__withdraw_amount": "Withdraw amount",
"ethereum__withdraw_from": "Withdraw from",
diff --git a/core/translations/order.json b/core/translations/order.json
index 00c5a55b..42de3c6a 100644
--- a/core/translations/order.json
+++ b/core/translations/order.json
@@ -1260,5 +1260,7 @@
"1258": "words__arguments",
"1259": "words__authorization",
"1260": "words__comm_continue",
- "1261": "words__function"
+ "1261": "words__function",
+ "1262": "ethereum__skip_to_hash",
+ "1263": "ethereum__view_data_and_hash"
}
diff --git a/core/translations/signatures.json b/core/translations/signatures.json
index 6a3f7b58..d57419b6 100644
--- a/core/translations/signatures.json
+++ b/core/translations/signatures.json
@@ -1,8 +1,8 @@
{
"current": {
- "merkle_root": "74a2af9c3fbfacac8a434365e2d3aea74301e881b39ebaf91658fb818ebb399d",
- "datetime": "2026-07-24T09:30:32.338781+00:00",
- "commit": "4941ceac6671cbb7de07b1f6d49614331cafa222"
+ "merkle_root": "a2d42d288133ef6351261442d3906bb2f51d752a6697c80d2d2d23710bd965b7",
+ "datetime": "2026-07-24T10:30:49.899834+00:00",
+ "commit": "d289db4b9546e33dcae0a69e40f0d1401ea724da"
},
"history": [
{
diff --git a/tests/input_flows.py b/tests/input_flows.py
index a54884a1..9ae7dad1 100644
--- a/tests/input_flows.py
+++ b/tests/input_flows.py
@@ -1762,6 +1762,13 @@ class InputFlowEthereumSignTxData(InputFlowBase):
is_intro = False
continue
+ if br.name == "confirm_digest":
+ content = self.debug.read_layout().text_content()
+ # TODO: read and verify hash (needs keccak256)
+ assert TR.ethereum__calldata_digest in content
+ self.debug.press_yes()
+ continue
+
# data confirmation is over - confirm tx details
if confirm_tx is None:
confirm_tx = self.confirm_tx
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index d8dff314..53acbc1d 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -24447,8 +24447,8 @@
"T3T1_cs_ethereum-test_signtx.py::test_signtx_data_bad_init": "9c20243bc5dacf2442af5a8778b66a0ab7cb978e11c02fec371f109fbc9d55f6",
"T3T1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "261e0311d5c5c0a7095d3169b9d77e97d729564fcaa07a90e8c2ab446ea8926d",
"T3T1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "7b71352e4ec49d0eec1e903b95bfdd6f3c70a9078658a39bc3431b2cb47a716c",
-"T3T1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "a31ba9c3068074f0b636971cca15f03b1f24aa850a0e2a9b7bf8d4d749f60eda",
-"T3T1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "d29d67fbbf90152508e0a3cab7a33b52a7cdfff41dc78cdaf1c6e45fa0fa6ced",
+"T3T1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "cfbc6bda1765d0722b5fb2b605c95374d753482a5b6945c85d21001f17576fd8",
+"T3T1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "b74ba228802f457bbf291e1da7eec2507697099df8ebffbd2ae451916fb8ec1a",
"T3T1_cs_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "7ad1e977ac8bca7a42b5710c9f272a16561798652e3aba07ea9284de6ab52399",
"T3T1_cs_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "d8707790c80c5adfb2ac7c75ea75bea9b062bb238dbbdf4d24ff5c7e0e8c1dba",
"T3T1_cs_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "1586f14140a233643d7423fb832f632e2ab9932207d0baa46de5e39f066691d5",
@@ -26243,8 +26243,8 @@
"T3T1_de_ethereum-test_signtx.py::test_signtx_data_bad_init": "68c146f13417be0845fee20b1d8de4a05e0844608c2efb3cfae9f573be39f0c4",
"T3T1_de_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "81cf7bfd1de144b36728df6f895c33f7c117ea39ca590f0e122a79e89b245c8d",
"T3T1_de_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "d250bcd0d6fa2eedd77c9766138975b09e56d510d3e90f7048b8beaef8479aac",
-"T3T1_de_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "538365c9f6a438a636586317a45f2a70e104ba5ee64ec757205bb53d77d3774d",
-"T3T1_de_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "4ef52f1137b908cdb1d9101fe804ca82fa48fc2f7f3d0778a8f62a5c1b3185b2",
+"T3T1_de_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "203ecfa55882526287f473c52e32925543016678a4f0a731b0d547eee7ba00be",
+"T3T1_de_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "0938ef3c5eb884cc0dfc783a4e473c8543027c1a0c8d615902a7eeb6bc8b6589",
"T3T1_de_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "a723f88dca892b00644e80857228cfe4a13186ad43ef2c2a563db0d4ca8cc56e",
"T3T1_de_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "46aba8d4ff318e200dead4cdcf3727d01a9052dfe529c94b730185c46a541a92",
"T3T1_de_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "6899fe0e62be0ec7eb5c8068db56d217cac5ef695e8e36a65eed42c55ea3fa32",
@@ -28039,8 +28039,8 @@
"T3T1_en_ethereum-test_signtx.py::test_signtx_data_bad_init": "0064e8a52b9bff0c2a31432fa781b800afb21e8910d60f303671bdfc8d8425fc",
"T3T1_en_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "f30e822517105f9f740f204b88e2394f580be00e7008f05fe844c0b0c3233bbe",
"T3T1_en_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "536a9b8b72b1511fccad288ac0ba5d2c5c766affe9fd235fa8529d1ca48e825a",
-"T3T1_en_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "d0e0413ee706a3befdd3e97ad87460e99574fb14b37aa2e2fc58a2234d473e05",
-"T3T1_en_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "d3993e399becb2307ad1c24523ce25c7bc7e9f9e4349e21068c71bc24f717196",
+"T3T1_en_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "c3bff932849852317728d7f0fd70844988f1d5f5ccb9dbe8342ac3146cce6fa4",
+"T3T1_en_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "4584097ccc7d56a9e7924826bffbe5d90de778599486f5874b27e48f63d6a60b",
"T3T1_en_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "c76c63563b2a1e97c4faa53f4fdac242209252d1e19101ce9ee9c4505a508239",
"T3T1_en_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "93e430c761dab2746df7fd54ca309998eff38ba591469cb7c5bd75af08f4db23",
"T3T1_en_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "b310b65e4a68967f33001d34bfcb18cdd239aa35420060f30634336b5b86b97a",
@@ -29835,8 +29835,8 @@
"T3T1_es_ethereum-test_signtx.py::test_signtx_data_bad_init": "41b9c9e85d64891dcfd03d675df77c533f035a2d191b161144d00afab69a589d",
"T3T1_es_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "83629acf49d8bfe51d718da26ef2ad9a4946687a707e338e75e0e3aee5ab397c",
"T3T1_es_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "92a9cb3cb973e33cec21ecb4b7540ea6169b7ba84312755ad166bbd28a019883",
-"T3T1_es_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "f4de1727439a3a80081960a40dae52ac53c30bf5dc8fce8393647fdff65bd52c",
-"T3T1_es_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "d1ca6a9ab7bd7612c26885aee9475f28e8b51d8505e93b09da87fcc721dfda7f",
+"T3T1_es_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "1ab3309950c1fc395b7f63900bfe0b4455a58a606b8c2933753356d647ede1e4",
+"T3T1_es_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "55ec438e911ccb7555bf3660f580c31aded4c3b4719837f842d46c160c254d02",
"T3T1_es_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "433ffee7e6a89e551a5c040ac56cb9207b6cb7557b77990bf177b3282401b84b",
"T3T1_es_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "b1ad9562100e72e92b7e84f88fa6c6ad2608192816451ee95c6693bb6a16b859",
"T3T1_es_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "b4c7f501d451cdc5b4780a59f0adeb362fc0f23e9faf96a25b49c241c7956dc6",
@@ -31631,8 +31631,8 @@
"T3T1_fr_ethereum-test_signtx.py::test_signtx_data_bad_init": "116c64aa168d12181b7a5317677ddf135d739fdac22d38ff08571dc3301c2f47",
"T3T1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "94846a295613f5d566a84fc3083469463c8e03714e25caa62a18b2299e8fef0d",
"T3T1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "1ab6a7658ab642232cd4585a5e9751ffb3597e4becbef9b2e48c82ba0be8248e",
-"T3T1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "9e997ba16022b5378d8be912a0ede19a67a8d205cc19839cc8ad544e7bef1b81",
-"T3T1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "f8009110c9b23713ce551d71a98c6fc64c8f3ec49801d4409fe54d3195c47cea",
+"T3T1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "98f1e30fc7263b4a23090da6c44a0659a046afd749e1d78a49b655a2ad6088b1",
+"T3T1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "ad85e8677ee84fdbf8a6a2d40016331ac8e39a33b105ac18b61bdeb8764d89b4",
"T3T1_fr_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "7afd98a9124ae7ef87b89ba628c3986747563d16060c02f14cbb01f1bddf96b9",
"T3T1_fr_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "031a96f4fef5122281cfe334d67bff4e827c5d6a65af6ee16d76c477f3d48194",
"T3T1_fr_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "dbacadb0238593d62a38a1724da07102dc5030776aed0117dd7f219b1db5f293",
@@ -33427,8 +33427,8 @@
"T3T1_pt_ethereum-test_signtx.py::test_signtx_data_bad_init": "14256cd1b801d1b67a37de1198d61a80d342f39e5c5d6fa991ec7fb526d683be",
"T3T1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "1d7cf31f580674519e514e87f68fa6973b3eeaa2c821e336400f43f66733e10f",
"T3T1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "351bd2c86d32b9e1b7722c798f70a14e303a8c8d8330a301c55c24af881701b9",
-"T3T1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "1823abe46d120364911c5b7e516adcdc3000d68c2ed0fa8c38f6788f2c85dc55",
-"T3T1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "6875e1213a9d38bbd80b40255bf55746d5ddf6be83e3a387bc8a8cc2e8a4e09c",
+"T3T1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "8676ec8debc6219bb8b0e7f6748a5779c3025ca622ba54a4c49accfbc2db143d",
+"T3T1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "11bbe2f4aa9a39158283092e78f6f3b7eb18811706a7a75d0f641539719b7591",
"T3T1_pt_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "11afff0b9754bd6d7496557eeca4a0b17350fa3e9a7c2cefa4472aa1e850a0e6",
"T3T1_pt_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "9efcbbc351ebd8f1b5c2ecb8facd65dc0f4b1e7e5d20341c910670031cdd2f32",
"T3T1_pt_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "4b839497bc0739b7fab46add6d253bac1b00c517f18a7cc9687c30bd27e9b3dc",
@@ -35875,8 +35875,8 @@
"T3W1_cs_ethereum-test_signtx.py::test_signtx_data_bad_init": "2b06a6c36a96faaad9d1237b47e37374c5452331ad8fa3738accbd2e09ec1500",
"T3W1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "ea7648298e2337f9ad1814756949adfd07d6d6c130e341f395b83e4372e6ab05",
"T3W1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "2bc8b5195910efd898cc21d523df4df0d62ef6697150c98ec251aa02219fa8f1",
-"T3W1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "a021833c857d5f2a57da5b13229636324b253e490a6994627693d84aab5f85ff",
-"T3W1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "f7bf8e1e41160a61ab33958dd06b489c3ffeaa0214468d5ce9d62994540b5e09",
+"T3W1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "8a6c3d270ae4b843745d42e0bfc673e2acc31dc62920715d681e465c14bbdd1d",
+"T3W1_cs_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "8bc8555fe7028dca1e853ea85c0ae5aa9bb2b45a7f987567c57b040959dcd0b2",
"T3W1_cs_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "12c35f44cd6e7c7a09c7f1791c7203e266e0644f886167d2e8b379072e125734",
"T3W1_cs_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "01665c01c66573c250846864bc9b3f49f12c0395db6993eabcce55b4ca1d4ea2",
"T3W1_cs_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "65f2fc45448b0247cb4f722b63fe82e4438f211b55e6187c04d96e5bd79737cd",
@@ -37706,8 +37706,8 @@
"T3W1_de_ethereum-test_signtx.py::test_signtx_data_bad_init": "32c06c9f4ef6d91d183e5480b273a0aec9bd56572528ddbfb70b7cd609cbef50",
"T3W1_de_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "e429c0b0f0a597da080da201099cf13c26c5ed425b398401b69bbbfe4a79f8c1",
"T3W1_de_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "396fb51b18ffd61de1b61afb70919b9e27d3d4cbc0c5f314994d1c3032afa7bc",
-"T3W1_de_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "2a349c91f55fdb30ea30359fa2a187771ea5dfe5d59296873e3c685a7d39999a",
-"T3W1_de_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "13d7bde6f92774ab10a95ab3b720c02eb98c5245cb2605bc27ba3769621ed345",
+"T3W1_de_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "0002d4238cbfd4b7eb28c676b8088242f2d26a96fa34752d6f2f880a240924ce",
+"T3W1_de_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "db40974c026739ad5c267b59c4919e47775b3d6c8859717da7a9346ed136b968",
"T3W1_de_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "67c114ffb677cddf9d03c7fcf91e265e7f8ca5a9569fd0049d89478f1b9edc98",
"T3W1_de_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "e31c52fb52d0e0c03493eee60a2746ac35a91f38d04d2c562079cb72242d0744",
"T3W1_de_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "66baac83c263045688430904f2067f3441f3ab62d7d9e0fb1a14d9d96e8093da",
@@ -39537,8 +39537,8 @@
"T3W1_en_ethereum-test_signtx.py::test_signtx_data_bad_init": "90812f196e8c35dc7f35cb5a9a0e553c8fc6a610812d85b9f166e90b3f1c8b59",
"T3W1_en_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "59119407fabd1430b5e75946e395e07755a6e7f91ec70f21ea063a84008d0d22",
"T3W1_en_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "df23da2f82149c8a6a701ad41ed3fc14b7ad278d05d87843ad8add3c1cf8af0d",
-"T3W1_en_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "798eb20f5e189973b07b331bb2459fb947dd7e6998ae19171f16c88acccf5732",
-"T3W1_en_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "0448e8b0e7d2957180920bf1f3cf5180f30093955bc49764d39fbaf3d74e404a",
+"T3W1_en_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "55968bb125106f797b707aec9ec6f61cf2600dd0dbc91121c6308a33994ea53f",
+"T3W1_en_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "4bc8cddfb03a5a64fcc7acf74820492bb4deee881fafd1a844ded63960d8637b",
"T3W1_en_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "f3c3a77aa48f55873934a2daba69a313fdc8ce20422cab16b951702c1184cc67",
"T3W1_en_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "4ac9d31b3ceeb8ecdb3febe8df14ea52f310e27474cf944d318c8a9d3ae5c21a",
"T3W1_en_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "a95a6516217175f5c5c8c014fe9899dd57494341a65b07e606a8151ae3b1a617",
@@ -41368,8 +41368,8 @@
"T3W1_es_ethereum-test_signtx.py::test_signtx_data_bad_init": "ddbd1412a9f69aea1c41c375a2ec0647411a0e487ec5c1ee55e24505dfc34e29",
"T3W1_es_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "8e0ed1164516add3b12a073999d3f1265be6f62c846ea83498df6af981206ffb",
"T3W1_es_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "637b6a8362f4b7569313d64ee455e26cdbf13c9217d436f8739821515b168d15",
-"T3W1_es_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "91e473f9445133c30a22babab861028c153f126925be8a5e9976657f9c0bc192",
-"T3W1_es_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "ff94663f02f293b33a27551277709ce057164d8c423f215d154c7a49671c0ed2",
+"T3W1_es_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "eb1c0b551bfe7e2e7c321230f621a0be16591151378dd4aabedbc94b33dc4a57",
+"T3W1_es_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "4d5ef561b887cc5ce4286f5b024912da9df75d08d4fd9f2a390f956e29e2ecbf",
"T3W1_es_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "2d738bfcbc921cad3a67ea97db7f10e06852ed5662c989ef95743f8c3307f88f",
"T3W1_es_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "659ba019e4d8f06474f5fb3653011c6308a2b5e6319c39d98d532503b72fb4a3",
"T3W1_es_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "7493ee184aa4e21119356f90bc9c3eae73456d2dc781986db38ec0d1b0560c0a",
@@ -43199,8 +43199,8 @@
"T3W1_fr_ethereum-test_signtx.py::test_signtx_data_bad_init": "a392ca1dea666647fb2d6edfcd90e4e3cad6ab0e294ca85cda7db478214a6a81",
"T3W1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "9ed0b2cdf203fc8a5caf5e3845b93d4ea34b51a62513324d288c025ec0b52498",
"T3W1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "4ce759614c2b067583fc54ab9a177998a3ce045177340333a6f5a5f05473d517",
-"T3W1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "f9eb68be6095df1635a57124576df2b1338cc53085234d3ed05ef2a105ab9a28",
-"T3W1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "f77ddd81fe943cf00b6c135350a2ff8e6de4cb812fd10ed0e6805c001ad1e81e",
+"T3W1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "e711d2398a4dd4f15c22e07a138f8170f9742a619d61cd45ab8d133b478867a5",
+"T3W1_fr_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "fd558079226edf8905a8a7e64bdde65fa1bd35d964993e341edb4210375410ec",
"T3W1_fr_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "2b542fc103310eb4369bde846add94e1d1bbbba6070ad1d526d115ed89113f58",
"T3W1_fr_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "aa4c101fa88d14eadffe997c5bcb4bb1855a65250dff132dcef70a83ae1af031",
"T3W1_fr_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "bd8133607b47e1aa037314b93110fc76889b1d3f5e15eeb874d633fb1a755f43",
@@ -45035,8 +45035,8 @@
"T3W1_pt_ethereum-test_signtx.py::test_signtx_data_bad_init": "6fb22dca4b252028ed3f91db1fb746e30d12aece0a74e1bcc4abef605a3a9026",
"T3W1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[False-10000]": "cc14acb2b67a921f3a4f6e37d2aa0ba29349cd3cd9afd3722c0080c1c80df587",
"T3W1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[False-176]": "2d51f26eb9c6855ea88db8b23644e93e514f30ec0bba3bb8fdf19404900d10fa",
-"T3W1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "3c301b6ce92fdf2ec3c781ef346c8a5b7e7705cee87298a6b43d85dcdb3a1927",
-"T3W1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "e576a371317de289d7916b318d5a5e7fa60afb7b67cb9490f1c8cd776d0729de",
+"T3W1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[True-10000]": "ec5dc800088701336ca10bfee3ee0aacb91b710ed7fbfed15353947280cf57d9",
+"T3W1_pt_ethereum-test_signtx.py::test_signtx_data_pagination[True-176]": "127e729b37fd3b951bf5b9d5c67b5656f3027d1db85464f7a9bac721d6edbf3d",
"T3W1_pt_ethereum-test_signtx.py::test_signtx_eip1559[False-Base]": "40fe0d5b85bc7cc147c437f27c9afa0c2a57b0d5f0a56aea9c0dbb60a222999f",
"T3W1_pt_ethereum-test_signtx.py::test_signtx_eip1559[False-Ledger Live legacy path]": "5dd0c5abf6439847903fb08c5a90520c37798d7cd78eaff75788797be6e71f4b",
"T3W1_pt_ethereum-test_signtx.py::test_signtx_eip1559[False-data_1]": "3d070a1896430792e04ebf4c8e97c530f41438f6e14c13f9c5648e6bdba79e9d",
Why this scored 35/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.