refactor(core): avoid allocation in `confirm_payment_request()`
What changed, and why it matters
This is a small internal code cleanup in the Trezor firmware's Ethereum transaction confirmation flow. It changes several function parameters from 'Iterable' (a general 'can be looped over' type) to 'Sequence' (a type that supports indexing and has a known length). The commit title says the goal is to 'avoid allocation' because the code no longer needs to convert the items into a list before passing them to the UI. There is no direct evidence in the commit of a security vulnerability being fixed; it reads as a performance or memory-efficiency refactor.
No immediate security action is required. Treat as a normal code-quality refactor. If reviewing for security, verify that upstream callers already supply a Sequence (e.g., a list or tuple) so the type change does not introduce runtime regressions, and that downstream consumers do not rely on the parameter being consumed only once.
Security signals we found
Type-hint-only refactor with no runtime validation changes
Removal of list() allocation in caesar confirm_payment_request
No explicit security claim in commit message or diff
No changes to cryptographic, parsing, or authorization code
No CVE, advisory, or researcher attribution present in supplied materials
Evidence from the diff
The diff refactors type hints and one call site in the Ethereum clear-signing and UI layout code. Functions such as get_fee_items_regular, get_fee_items_eip1559, try_confirm, _handle_transfer, confirm_tx_data, require_confirm_payment_request, and the per-theme confirm_payment_request implementations change their fee/account item parameters from Iterable[StrPropertyType] to Sequence[StrPropertyType]. In the caesar layout, the previous code called list(fee_info_items) and list(account_items) to materialize iterables before passing them to create_details; after the change it passes the Sequence directly. This avoids a runtime list allocation. No logic changes, bounds checks, or input validation are added.
Changed components
core/src/apps/ethereum/clear_signing.pycore/src/apps/ethereum/helpers.pycore/src/apps/ethereum/layout.pycore/src/apps/ethereum/sign_tx.pycore/src/trezor/ui/layouts/bolt/__init__.pycore/src/trezor/ui/layouts/caesar/__init__.pycore/src/trezor/ui/layouts/delizia/__init__.pycore/src/trezor/ui/layouts/eckhart/__init__.pyInspect captured patch +23 / −23
diff --git a/core/src/apps/ethereum/clear_signing.py b/core/src/apps/ethereum/clear_signing.py
index 02e08549..547ac454 100644
--- a/core/src/apps/ethereum/clear_signing.py
+++ b/core/src/apps/ethereum/clear_signing.py
@@ -14,7 +14,7 @@ from .helpers import (
if TYPE_CHECKING:
from buffer_types import AnyBytes
- from typing import Callable, Iterable
+ from typing import Callable, Iterable, Sequence
from trezor.messages import (
EthereumABIValueInfo,
@@ -835,7 +835,7 @@ async def try_confirm(
msg: MsgInSignTx,
defs: Definitions,
maximum_fee: str,
- fee_items: Iterable[StrPropertyType],
+ fee_items: Sequence[StrPropertyType],
payment_request_verifier: PaymentRequestVerifier | None,
) -> bool:
from .clear_signing_definitions import (
@@ -986,7 +986,7 @@ async def _handle_transfer(
msg: MsgInSignTx,
defs: Definitions,
maximum_fee: str,
- fee_items: Iterable[StrPropertyType],
+ fee_items: Sequence[StrPropertyType],
payment_request_verifier: PaymentRequestVerifier | None,
) -> None:
from .layout import require_confirm_payment_request, require_confirm_tx
diff --git a/core/src/apps/ethereum/helpers.py b/core/src/apps/ethereum/helpers.py
index 063907ff..2b0b6776 100644
--- a/core/src/apps/ethereum/helpers.py
+++ b/core/src/apps/ethereum/helpers.py
@@ -7,7 +7,7 @@ from . import networks
if TYPE_CHECKING:
from buffer_types import AnyBytes
- from typing import Awaitable, Callable, Iterable
+ from typing import Awaitable, Callable, Sequence
from trezor.messages import EthereumFieldType, EthereumTokenInfo
from trezor.ui.layouts import StrPropertyType
@@ -136,7 +136,7 @@ def decode_typed_data(data: AnyBytes, type_name: str) -> str:
def get_fee_items_regular(
gas_price: int, gas_limit: int, network: EthereumNetworkInfo
-) -> Iterable[StrPropertyType]:
+) -> Sequence[StrPropertyType]:
# regular
gas_limit_str = TR.ethereum__units_template.format(gas_limit)
gas_price_str = format_ethereum_amount(
@@ -154,7 +154,7 @@ def get_fee_items_eip1559(
max_priority_fee: int,
gas_limit: int,
network: EthereumNetworkInfo,
-) -> Iterable[StrPropertyType]:
+) -> Sequence[StrPropertyType]:
# EIP-1559
gas_limit_str = TR.ethereum__units_template.format(gas_limit)
max_gas_fee_str = format_ethereum_amount(
diff --git a/core/src/apps/ethereum/layout.py b/core/src/apps/ethereum/layout.py
index 9374f9c4..e922d717 100644
--- a/core/src/apps/ethereum/layout.py
+++ b/core/src/apps/ethereum/layout.py
@@ -21,7 +21,7 @@ from .helpers import (
if TYPE_CHECKING:
from buffer_types import AnyBytes
- from typing import Awaitable, Iterable
+ from typing import Awaitable, Iterable, Sequence
from trezor.messages import (
EthereumFieldType,
@@ -141,7 +141,7 @@ async def require_confirm_payment_request(
verified_payment_req: PaymentRequest,
address_n: list[int],
maximum_fee: str,
- fee_info_items: Iterable[StrPropertyType],
+ fee_info_items: Sequence[StrPropertyType],
chain_id: int,
network: EthereumNetworkInfo,
token: EthereumTokenInfo | None,
diff --git a/core/src/apps/ethereum/sign_tx.py b/core/src/apps/ethereum/sign_tx.py
index 0a05ddeb..eca86df7 100644
--- a/core/src/apps/ethereum/sign_tx.py
+++ b/core/src/apps/ethereum/sign_tx.py
@@ -18,7 +18,7 @@ from .keychain import with_keychain_from_chain_id
if TYPE_CHECKING:
from buffer_types import AnyBytes
- from typing import Any, Coroutine, Iterable
+ from typing import Any, Coroutine, Sequence
from trezor.messages import EthereumSignTx, EthereumTxAck
from trezor.ui.layouts import StrPropertyType
@@ -221,7 +221,7 @@ async def confirm_tx_data(
tx_type: int | None,
address_bytes: bytes,
maximum_fee: str,
- fee_items: Iterable[StrPropertyType],
+ fee_items: Sequence[StrPropertyType],
payment_request_verifier: PaymentRequestVerifier | None,
sender_bytes: AnyBytes,
) -> tuple[ConfirmDataFn | None, Coroutine[Any, Any, None] | None]:
diff --git a/core/src/trezor/ui/layouts/bolt/__init__.py b/core/src/trezor/ui/layouts/bolt/__init__.py
index 23d6d2eb..6ced37d0 100644
--- a/core/src/trezor/ui/layouts/bolt/__init__.py
+++ b/core/src/trezor/ui/layouts/bolt/__init__.py
@@ -496,9 +496,9 @@ async def confirm_payment_request(
texts: Iterable[tuple[str | None, str]],
refunds: Iterable[Refund],
trades: list[Trade],
- account_items: Iterable[StrPropertyType] | None,
+ account_items: Sequence[StrPropertyType] | None,
transaction_fee: str | None,
- fee_info_items: Iterable[StrPropertyType] | None,
+ fee_info_items: Sequence[StrPropertyType] | None,
extra_menu_items: list[tuple[str, str]] | None = None,
) -> None:
from ..slip24 import is_swap
diff --git a/core/src/trezor/ui/layouts/caesar/__init__.py b/core/src/trezor/ui/layouts/caesar/__init__.py
index 89713dec..e1b3d00d 100644
--- a/core/src/trezor/ui/layouts/caesar/__init__.py
+++ b/core/src/trezor/ui/layouts/caesar/__init__.py
@@ -557,9 +557,9 @@ async def confirm_payment_request(
texts: Iterable[tuple[str | None, str]],
refunds: Iterable[Refund],
trades: list[Trade],
- account_items: Iterable[StrPropertyType],
+ account_items: Sequence[StrPropertyType],
transaction_fee: str | None,
- fee_info_items: Iterable[StrPropertyType] | None,
+ fee_info_items: Sequence[StrPropertyType] | None,
extra_menu_items: list[tuple[str, str]] | None = None,
) -> None:
from trezor.ui.layouts.menu import Menu, confirm_with_menu
@@ -638,8 +638,8 @@ async def confirm_payment_request(
)
summary_menu_items = [
- create_details(TR.confirm_total__title_fee, list(fee_info_items)),
- create_details(TR.address_details__account_info, list(account_items)),
+ create_details(TR.confirm_total__title_fee, fee_info_items),
+ create_details(TR.address_details__account_info, account_items),
]
summary_menu = Menu.root(summary_menu_items)
@@ -2400,7 +2400,7 @@ async def confirm_firmware_update(description: str, fingerprint: str) -> None:
)
-def create_details(name: str, value: list[StrPropertyType] | str) -> Details:
+def create_details(name: str, value: Sequence[StrPropertyType] | str) -> Details:
from trezor.ui.layouts.menu import Details
return Details.from_layout(
diff --git a/core/src/trezor/ui/layouts/delizia/__init__.py b/core/src/trezor/ui/layouts/delizia/__init__.py
index 6cf649ca..4544669c 100644
--- a/core/src/trezor/ui/layouts/delizia/__init__.py
+++ b/core/src/trezor/ui/layouts/delizia/__init__.py
@@ -486,9 +486,9 @@ async def confirm_payment_request(
texts: Iterable[tuple[str | None, str]],
refunds: Iterable[Refund],
trades: list[Trade],
- account_items: Iterable[StrPropertyType] | None,
+ account_items: Sequence[StrPropertyType] | None,
transaction_fee: str | None,
- fee_info_items: Iterable[StrPropertyType] | None,
+ fee_info_items: Sequence[StrPropertyType] | None,
extra_menu_items: list[tuple[str, str]] | None = None,
) -> None:
from trezor.ui.layouts.menu import Menu, confirm_with_menu
@@ -2321,7 +2321,7 @@ async def tutorial(br_code: ButtonRequestType = BR_CODE_OTHER) -> None:
def create_details(
name: str,
- value: list[StrPropertyType] | str,
+ value: Sequence[StrPropertyType] | str,
title: str | None = None,
) -> Details:
from trezor.ui.layouts.menu import Details
diff --git a/core/src/trezor/ui/layouts/eckhart/__init__.py b/core/src/trezor/ui/layouts/eckhart/__init__.py
index 9de0a5a9..c38c5018 100644
--- a/core/src/trezor/ui/layouts/eckhart/__init__.py
+++ b/core/src/trezor/ui/layouts/eckhart/__init__.py
@@ -449,9 +449,9 @@ async def confirm_payment_request(
texts: Iterable[tuple[str | None, str]],
refunds: Iterable[Refund],
trades: list[Trade],
- account_items: Iterable[StrPropertyType],
+ account_items: Sequence[StrPropertyType],
transaction_fee: str | None,
- fee_info_items: Iterable[StrPropertyType] | None,
+ fee_info_items: Sequence[StrPropertyType] | None,
extra_menu_items: list[tuple[str, str]] | None = None,
) -> None:
from trezor.ui.layouts.menu import Menu, confirm_with_menu
@@ -2446,7 +2446,7 @@ async def tutorial(br_code: ButtonRequestType = BR_CODE_OTHER) -> None:
def create_details(
name: str,
- value: list[StrPropertyType] | str,
+ value: Sequence[StrPropertyType] | str,
title: str | None = None,
subtitle: str | None = None,
) -> Details:
Why this scored 18/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.