chore(ethereum): Move stablecoin yielding from debug to production.
What changed, and why it matters
This commit moves an Ethereum feature called "stablecoin yielding" from debug-only mode into production. It adds user-interface flows for certain ERC-4626 vault interactions, such as depositing USDC into a yield-bearing vault. The change itself is a feature promotion, not a fix for a known security flaw. There is no evidence in the commit that it addresses an active vulnerability or that it introduces one.
Treat as a routine feature-enablement commit. Review the yielding approver logic separately for correctness and UI safety, but no immediate security response is indicated by this diff alone.
Security signals we found
Feature promotion from debug to production, not a vulnerability patch
No new input validation, memory safety, or cryptographic hardening visible in diff
No vendor statement of security relevance in commit message or changelog
No independent researcher attribution in commit materials
Evidence from the diff
The patch removes if __debug__: guards around stablecoin-yielding vault handling in Trezor’s Ethereum app. It makes yielding_vaults.py and its lookup_vault function available in production firmware, registers a known test vault address in sc_constants.py, and enables sign_tx.py to return a yielding transaction approver outside debug builds. A changelog fragment notes “Added UI flows for some ERC-4626 vault interactions.” No security-relevant bug fix, bounds check, or cryptographic change is present in the diff.
Changed components
core/src/apps/ethereum/sign_tx.pycore/src/apps/ethereum/yielding_vaults.pycore/src/apps/ethereum/sc_constants.pyInspect captured patch +53 / −56
diff --git a/core/.changelog.d/6435.added b/core/.changelog.d/6435.added
new file mode 100644
index 00000000..5b9988e2
--- /dev/null
+++ b/core/.changelog.d/6435.added
@@ -0,0 +1 @@
+Added UI flows for some ERC-4626 vault interactions.
diff --git a/core/src/apps/ethereum/sc_constants.py b/core/src/apps/ethereum/sc_constants.py
index 5ccb1a56..bb8c3c6b 100644
--- a/core/src/apps/ethereum/sc_constants.py
+++ b/core/src/apps/ethereum/sc_constants.py
@@ -12,7 +12,3 @@ KNOWN_ADDRESSES = {
# https://etherscan.io/address/0xe592427a0aece92de3edee1f18e0157c05861564
unhexlify("e592427a0aece92de3edee1f18e0157c05861564"): "Uniswap V3 Router",
}
-if __debug__:
- from .yielding_vaults import KNOWN_VAULT
-
- KNOWN_ADDRESSES[KNOWN_VAULT[0]] = KNOWN_VAULT[2]
diff --git a/core/src/apps/ethereum/sign_tx.py b/core/src/apps/ethereum/sign_tx.py
index 36e538ec..abaaf806 100644
--- a/core/src/apps/ethereum/sign_tx.py
+++ b/core/src/apps/ethereum/sign_tx.py
@@ -236,14 +236,13 @@ async def confirm_tx_data(
raise DataError("Payment Requests don't support staking")
return staking_approver
- if __debug__:
- yielding_approver = yielding.get_approver(
- msg, network, address_bytes, maximum_fee, fee_items, sender_bytes
- )
- if yielding_approver is not None:
- if payment_request_verifier is not None:
- raise DataError("Payment Requests don't support yielding")
- return yielding_approver
+ yielding_approver = yielding.get_approver(
+ msg, network, address_bytes, maximum_fee, fee_items, sender_bytes
+ )
+ if yielding_approver is not None:
+ if payment_request_verifier is not None:
+ raise DataError("Payment Requests don't support yielding")
+ return yielding_approver
if tx_type == _EIP_7702_TX_TYPE:
# we have already made sure that the address is a known address
diff --git a/core/src/apps/ethereum/yielding_vaults.py b/core/src/apps/ethereum/yielding_vaults.py
index cc2a8bb6..322dd584 100644
--- a/core/src/apps/ethereum/yielding_vaults.py
+++ b/core/src/apps/ethereum/yielding_vaults.py
@@ -1,49 +1,50 @@
-if __debug__:
- from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING
- if TYPE_CHECKING:
- from buffer_types import AnyBytes
+if TYPE_CHECKING:
+ from buffer_types import AnyBytes
+ from trezor.messages import EthereumNetworkInfo
- from trezor.messages import EthereumNetworkInfo, EthereumTokenInfo
+from trezor.messages import EthereumTokenInfo
- # Stablecoin Yielding Vaults
- # Will be a list of tuples for each chain/network.
- KNOWN_VAULT = (
- # Test vault: https://etherscan.io/address/0xa511d618cD0F9d7cAD791009d7c5E3b19c9568da
- b"\xa5\x11\xd6\x18\xcd\x0f\x9d\x7c\xad\x79\x10\x09\xd7\xc5\xe3\xb1\x9c\x95\x68\xda", # vault contract address
- 1, # chain id (Ethereum)
- "Test Steakhouse USDC Prime Vault", # owner/protocol name
- # Asset Token
- EthereumTokenInfo(
- symbol="USDC",
- decimals=6,
- address=b"\xa0\xb8\x69\x91\xc6\x21\x8b\x36\xc1\xd1\x9d\x4a\x2e\x9e\xb0\xce\x36\x06\xeb\x48",
- chain_id=1,
- name="USD Coin",
- ),
- # Vault token
- EthereumTokenInfo(
- symbol="tstSHUSDCp",
- decimals=18,
- address=b"\xa5\x11\xd6\x18\xcd\x0f\x9d\x7c\xad\x79\x10\x09\xd7\xc5\xe3\xb1\x9c\x95\x68\xda", # vault contract address
- chain_id=1,
- name="Test Steakhouse USDC Prime",
- ),
- )
+# Stablecoin Yielding Vaults
+# Will be a list of tuples for each chain/network.
+KNOWN_VAULT = (
+ # Test vault: https://etherscan.io/address/0xa511d618cD0F9d7cAD791009d7c5E3b19c9568da
+ b"\xa5\x11\xd6\x18\xcd\x0f\x9d\x7c\xad\x79\x10\x09\xd7\xc5\xe3\xb1\x9c\x95\x68\xda", # vault contract address
+ 1, # chain id (Ethereum)
+ "Test Steakhouse USDC Prime Vault", # owner/protocol name
+ # Asset Token
+ EthereumTokenInfo(
+ symbol="USDC",
+ decimals=6,
+ address=b"\xa0\xb8\x69\x91\xc6\x21\x8b\x36\xc1\xd1\x9d\x4a\x2e\x9e\xb0\xce\x36\x06\xeb\x48",
+ chain_id=1,
+ name="USD Coin",
+ ),
+ # Vault token
+ EthereumTokenInfo(
+ symbol="tstSHUSDCp",
+ decimals=18,
+ address=b"\xa5\x11\xd6\x18\xcd\x0f\x9d\x7c\xad\x79\x10\x09\xd7\xc5\xe3\xb1\x9c\x95\x68\xda", # vault contract address
+ chain_id=1,
+ name="Test Steakhouse USDC Prime",
+ ),
+)
- def lookup_vault(
- network: EthereumNetworkInfo, vault_addr: AnyBytes
- ) -> tuple[bool, str, EthereumTokenInfo, EthereumTokenInfo]:
- """returns (is_known_vault, vault_name_or_address, asset_token, vault_token)"""
- from .helpers import address_from_bytes
- from .tokens import UNKNOWN_TOKEN
- if network.chain_id == KNOWN_VAULT[1] and vault_addr == KNOWN_VAULT[0]:
- return True, KNOWN_VAULT[2], KNOWN_VAULT[3], KNOWN_VAULT[4]
- else:
- return (
- False,
- address_from_bytes(vault_addr, network),
- UNKNOWN_TOKEN,
- UNKNOWN_TOKEN,
- )
+def lookup_vault(
+ network: EthereumNetworkInfo, vault_addr: AnyBytes
+) -> tuple[bool, str, EthereumTokenInfo, EthereumTokenInfo]:
+ """Returns (is_known_vault, vault_name_or_address, asset_token, vault_token)"""
+ from .helpers import address_from_bytes
+ from .tokens import UNKNOWN_TOKEN
+
+ if network.chain_id == KNOWN_VAULT[1] and vault_addr == KNOWN_VAULT[0]:
+ return True, KNOWN_VAULT[2], KNOWN_VAULT[3], KNOWN_VAULT[4]
+ else:
+ return (
+ False,
+ address_from_bytes(vault_addr, network),
+ UNKNOWN_TOKEN,
+ UNKNOWN_TOKEN,
+ )
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.