feat(clear_signing): support sliced paths.
What changed, and why it matters
This commit adds a new feature to Trezor's Ethereum 'clear signing' system that lets wallet definitions extract a slice of bytes from a numeric parameter. For example, a 32-byte number that secretly packs an address into its last 20 bytes can now be sliced so the device shows only the real address. The change is described as a feature, not a bug fix, and there is no vendor statement that it fixes a security vulnerability. It does reduce one real risk: users could otherwise be tricked into approving transactions where hidden extra bits in a number change the meaning of what they see on screen.
Treat as a defensive feature addition. Review that all format definitions using sliced paths are themselves trustworthy, since a malicious definition could still mis-slice values. Ensure slice bounds are validated and consider adding runtime checks for slice steps that exceed the 32-byte word size.
Security signals we found
Feature adds ability to display only a byte slice of a larger numeric field, which can prevent UI spoofing when high bits of a packed value carry flags or a different address
New validation rejects byte-slicing negative signed integers
No changelog entry and commit message frames change as a feature, not a security fix
No CVE, advisory, or vendor security disclosure supplied or referenced
Evidence from the diff
The patch extends the EthereumERC7730Path protobuf message with optional slice_start and slice_end fields and implements byte-slicing in core/src/apps/ethereum/clear_signing.py. A new helper _word_bytes converts positive ints to 32-byte big-endian representations before slicing; negative signed ints raise InvalidFormatDefinition. The path walker now appends slice steps as tuples and applies them after converting numeric values to bytes. DateFormatter was updated to accept a sliced 4-byte big-endian timestamp. Tests cover packed-address extraction (1inch-style Address), packed-date extraction, and rejection of slicing negative signed ints.
Changed components
common/protob/messages-definitions.protocore/src/apps/ethereum/clear_signing.pycore/src/trezor/messages.pypython/src/trezorlib/messages.pyrust/trezor-client/src/protos/generated/messages_definitions.rsEthereum clear-signing / ERC-7730 display-format parsingInspect captured patch +244 / −42
diff --git a/common/protob/messages-definitions.proto b/common/protob/messages-definitions.proto
index d9d81366..c4ef3bd8 100644
--- a/common/protob/messages-definitions.proto
+++ b/common/protob/messages-definitions.proto
@@ -167,6 +167,8 @@ message EthereumERC7730Path {
repeated sint32 path = 1; // eg. (0,) is encoded as [0], (1, 2) is encoded as [1, 2], etc.
optional EthereumERC7730ContainerPath container_path = 2;
optional string const_value = 3; // a literal constant value, not walked from calldata
+ optional sint32 slice_start = 4;
+ optional sint32 slice_end = 5;
}
/**
diff --git a/core/src/apps/ethereum/clear_signing.py b/core/src/apps/ethereum/clear_signing.py
index 171ff166..87c8f2b0 100644
--- a/core/src/apps/ethereum/clear_signing.py
+++ b/core/src/apps/ethereum/clear_signing.py
@@ -162,6 +162,19 @@ def make_int_parser(bit_width: int) -> Parser:
return parser
+def _word_bytes(value: AnyValue) -> AnyValue:
+ """An EVM word can be viewed as an integer or as 32 bytes. A byte-slice
+ step selects the bytes view: e.g. `token.[-20:]` reads the low 20 bytes
+ of a uint256 (the 1inch packed `Address` type). Non-numeric values are
+ returned unchanged - they are sliced directly."""
+ if type(value) is int: # not isinstance: bool is an int subclass
+ if value < 0:
+ # byte-slicing a signed value has no defined meaning
+ raise InvalidFormatDefinition
+ return value.to_bytes(_EVM_WORD_SIZE, "big")
+ return value
+
+
def parse_bool(raw_data: memoryview) -> Value:
if len(raw_data) < _EVM_WORD_SIZE:
raise OutOfBounds
@@ -475,6 +488,9 @@ class DateFormatter(FieldFormatter):
if value is None:
return None, None, None
+ if isinstance(value, (bytes, bytearray)):
+ # a sliced word, e.g. `goodUntil.[-4:]`: big-endian seconds
+ value = int.from_bytes(value, "big")
if isinstance(value, int):
return format_timestamp(value), None, None
raise InvalidFormatDefinition
@@ -778,7 +794,13 @@ class FieldDefinition:
# A literal constant value, resolved by the parser — not walked
# from calldata. Rendered as-is (typically by the raw formatter).
return p.const_value
- return tuple(p.path)
+ steps: list[int | tuple[int] | tuple[int, int]] = list(p.path)
+ if p.slice_end is not None:
+ # `data.[0:20]` or `takerTraits.[:1]` (start defaults to 0)
+ steps.append((p.slice_start or 0, p.slice_end))
+ elif p.slice_start is not None:
+ steps.append((p.slice_start,)) # `token.[-20:]`
+ return tuple(steps)
path = decode_path(info.path)
@@ -911,6 +933,9 @@ class DisplayFormat:
if p is None:
p = None
break
+ if isinstance(step, tuple):
+ # slices view numeric values as bytes (see _word_bytes)
+ p = _word_bytes(p)
if isinstance(p, (list, tuple, bytes)):
# walk inside Arrays or Tuples
try:
diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py
index eaab35eb..9f2a32bd 100644
--- a/core/src/trezor/messages.py
+++ b/core/src/trezor/messages.py
@@ -3374,6 +3374,8 @@ if TYPE_CHECKING:
path: "list[int]"
container_path: "EthereumERC7730ContainerPath | None"
const_value: "str | None"
+ slice_start: "int | None"
+ slice_end: "int | None"
def __init__(
self,
@@ -3381,6 +3383,8 @@ if TYPE_CHECKING:
path: "list[int] | None" = None,
container_path: "EthereumERC7730ContainerPath | None" = None,
const_value: "str | None" = None,
+ slice_start: "int | None" = None,
+ slice_end: "int | None" = None,
) -> None:
pass
diff --git a/core/tests/test_apps.ethereum.clear_signing.py b/core/tests/test_apps.ethereum.clear_signing.py
index 964598be..9d68428c 100644
--- a/core/tests/test_apps.ethereum.clear_signing.py
+++ b/core/tests/test_apps.ethereum.clear_signing.py
@@ -589,7 +589,13 @@ class TestEthereumClearSigning(unittest.TestCase):
formatted, _, _ = await_result(fmt.format(None, None, None, None))
self.assertIsNone(formatted)
- # non-int value is rejected
+ # a sliced word, e.g. `goodUntil.[-4:]`: big-endian seconds
+ formatted, _, _ = await_result(
+ fmt.format((1616051824).to_bytes(4, "big"), None, None, None)
+ )
+ self.assertEqual(formatted, "2021-03-18 07:17:04")
+
+ # non-timestamp value is rejected
with self.assertRaises(InvalidFormatDefinition):
await_result(fmt.format("not-a-timestamp", None, None, None))
@@ -790,6 +796,89 @@ class TestEthereumClearSigning(unittest.TestCase):
self.assertIsNone(token)
self.assertIsNone(token_address)
+ # --- path byte-slices (`token.[-20:]` etc.) ---
+
+ def test_from_proto_path_slice(self):
+ # The optional terminal slice decodes into a trailing step tuple.
+ def decoded(**kwargs):
+ info = EthereumERC7730FieldInfo(
+ path=EthereumERC7730Path(**kwargs),
+ label="Field",
+ formatter=FT.FORMATTER_RAW,
+ )
+ return FieldDefinition.from_proto(info).path
+
+ self.assertEqual(decoded(path=[0]), (0,))
+ # token.[-20:]
+ self.assertEqual(decoded(path=[0], slice_start=-20), (0, (-20,)))
+ # params.path.[0:20]
+ self.assertEqual(
+ decoded(path=[1, 0], slice_start=0, slice_end=20), (1, 0, (0, 20))
+ )
+ # takerTraits.[:1] - start defaults to 0
+ self.assertEqual(decoded(path=[2], slice_end=1), (2, (0, 1)))
+
+ def test_packed_address_slice_end_to_end(self):
+ # The 1inch `Address` pattern: a uint256 whose low 20 bytes are an
+ # address and whose high bits carry flags. The parameter parses as a
+ # plain uint256 (faithful to the ABI); the field's `[-20:]` slice
+ # views the value as its EVM word and clips the flags (_word_bytes).
+ # The second parameter is the `goodUntil.[-4:]` shape: a date packed
+ # into the low bytes of a bytes32.
+ class _Defs:
+ network = make_eth_network()
+
+ addr_hex = "d8da6bf26964af9d7eed9e03e53415d37aa96045"
+ flags = (1 << 255) | (1 << 160)
+ packed_address = flags | int.from_bytes(unhexlify(addr_hex), "big")
+
+ display_format = DisplayFormat(
+ binding_context=None,
+ func_sig=b"\x00\x00\x00\x00",
+ provider_name=None,
+ intent="Test",
+ parameter_definitions=[
+ Atomic(parse_uint256), # packed address
+ Atomic(parse_bytes32), # packed date
+ ],
+ field_definitions=[
+ FieldDefinition((0, (-20,)), "Beneficiary", AddressNameFormatter),
+ FieldDefinition((1, (-4,)), "Expires", DateFormatter),
+ ],
+ )
+
+ calldata = to_bytes(packed_address) + to_bytes(1616051824)
+ parameters, fields = await_result(
+ display_format.parse_calldata(memoryview(calldata), None, _Defs())
+ )
+
+ # the parsed parameter keeps the full packed value
+ self.assertEqual(parameters[0], packed_address)
+
+ (label, formatted, _), _, _ = fields[0]
+ self.assertEqual(label, "Beneficiary")
+ self.assertEqual(formatted.lower(), "0x" + addr_hex)
+
+ (label, formatted, _), _, _ = fields[1]
+ self.assertEqual(label, "Expires")
+ self.assertEqual(formatted, "2021-03-18 07:17:04")
+
+ def test_slice_of_negative_int_rejected(self):
+ # Byte-slicing a signed value has no defined meaning.
+ display_format = DisplayFormat(
+ binding_context=None,
+ func_sig=b"\x00\x00\x00\x00",
+ provider_name=None,
+ intent="Test",
+ parameter_definitions=[Atomic(parse_int160)],
+ field_definitions=[FieldDefinition((0, (-20,)), "Field", RawFormatter)],
+ )
+ minus_one = ((1 << 256) - 1).to_bytes(32, "big")
+ with self.assertRaises(InvalidFormatDefinition):
+ await_result(
+ display_format.parse_calldata(memoryview(minus_one), None, None)
+ )
+
# --- tokenAmount with a constant (literal) token address ---
def test_from_proto_token_amount_constant_token(self):
diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py
index e8a5a208..4c6a2a59 100644
--- a/python/src/trezorlib/messages.py
+++ b/python/src/trezorlib/messages.py
@@ -4827,6 +4827,8 @@ class EthereumERC7730Path(protobuf.MessageType):
1: protobuf.Field("path", "sint32", repeated=True, required=False, default=None),
2: protobuf.Field("container_path", "EthereumERC7730ContainerPath", repeated=False, required=False, default=None),
3: protobuf.Field("const_value", "string", repeated=False, required=False, default=None),
+ 4: protobuf.Field("slice_start", "sint32", repeated=False, required=False, default=None),
+ 5: protobuf.Field("slice_end", "sint32", repeated=False, required=False, default=None),
}
def __init__(
@@ -4835,10 +4837,14 @@ class EthereumERC7730Path(protobuf.MessageType):
path: Optional[Sequence["int"]] = None,
container_path: Optional["EthereumERC7730ContainerPath"] = None,
const_value: Optional["str"] = None,
+ slice_start: Optional["int"] = None,
+ slice_end: Optional["int"] = None,
) -> None:
self.path: Sequence["int"] = path if path is not None else []
self.container_path = container_path
self.const_value = const_value
+ self.slice_start = slice_start
+ self.slice_end = slice_end
class EthereumERC7730FieldInfo(protobuf.MessageType):
diff --git a/rust/trezor-client/src/protos/generated/messages_definitions.rs b/rust/trezor-client/src/protos/generated/messages_definitions.rs
index bf9853ae..9f27282e 100644
--- a/rust/trezor-client/src/protos/generated/messages_definitions.rs
+++ b/rust/trezor-client/src/protos/generated/messages_definitions.rs
@@ -1362,6 +1362,10 @@ pub struct EthereumERC7730Path {
pub container_path: ::std::option::Option<::protobuf::EnumOrUnknown<EthereumERC7730ContainerPath>>,
// @@protoc_insertion_point(field:hw.trezor.messages.definitions.EthereumERC7730Path.const_value)
pub const_value: ::std::option::Option<::std::string::String>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.definitions.EthereumERC7730Path.slice_start)
+ pub slice_start: ::std::option::Option<i32>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.definitions.EthereumERC7730Path.slice_end)
+ pub slice_end: ::std::option::Option<i32>,
// special fields
// @@protoc_insertion_point(special_field:hw.trezor.messages.definitions.EthereumERC7730Path.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -1436,8 +1440,46 @@ impl EthereumERC7730Path {
self.const_value.take().unwrap_or_else(|| ::std::string::String::new())
}
+ // optional sint32 slice_start = 4;
+
+ pub fn slice_start(&self) -> i32 {
+ self.slice_start.unwrap_or(0)
+ }
+
+ pub fn clear_slice_start(&mut self) {
+ self.slice_start = ::std::option::Option::None;
+ }
+
+ pub fn has_slice_start(&self) -> bool {
+ self.slice_start.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_slice_start(&mut self, v: i32) {
+ self.slice_start = ::std::option::Option::Some(v);
+ }
+
+ // optional sint32 slice_end = 5;
+
+ pub fn slice_end(&self) -> i32 {
+ self.slice_end.unwrap_or(0)
+ }
+
+ pub fn clear_slice_end(&mut self) {
+ self.slice_end = ::std::option::Option::None;
+ }
+
+ pub fn has_slice_end(&self) -> bool {
+ self.slice_end.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_slice_end(&mut self, v: i32) {
+ self.slice_end = ::std::option::Option::Some(v);
+ }
+
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
- let mut fields = ::std::vec::Vec::with_capacity(3);
+ let mut fields = ::std::vec::Vec::with_capacity(5);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"path",
@@ -1454,6 +1496,16 @@ impl EthereumERC7730Path {
|m: &EthereumERC7730Path| { &m.const_value },
|m: &mut EthereumERC7730Path| { &mut m.const_value },
));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "slice_start",
+ |m: &EthereumERC7730Path| { &m.slice_start },
+ |m: &mut EthereumERC7730Path| { &mut m.slice_start },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "slice_end",
+ |m: &EthereumERC7730Path| { &m.slice_end },
+ |m: &mut EthereumERC7730Path| { &mut m.slice_end },
+ ));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<EthereumERC7730Path>(
"EthereumERC7730Path",
fields,
@@ -1484,6 +1536,12 @@ impl ::protobuf::Message for EthereumERC7730Path {
26 => {
self.const_value = ::std::option::Option::Some(is.read_string()?);
},
+ 32 => {
+ self.slice_start = ::std::option::Option::Some(is.read_sint32()?);
+ },
+ 40 => {
+ self.slice_end = ::std::option::Option::Some(is.read_sint32()?);
+ },
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -1505,6 +1563,12 @@ impl ::protobuf::Message for EthereumERC7730Path {
if let Some(v) = self.const_value.as_ref() {
my_size += ::protobuf::rt::string_size(3, &v);
}
+ if let Some(v) = self.slice_start {
+ my_size += ::protobuf::rt::sint32_size(4, v);
+ }
+ if let Some(v) = self.slice_end {
+ my_size += ::protobuf::rt::sint32_size(5, v);
+ }
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -1520,6 +1584,12 @@ impl ::protobuf::Message for EthereumERC7730Path {
if let Some(v) = self.const_value.as_ref() {
os.write_string(3, v)?;
}
+ if let Some(v) = self.slice_start {
+ os.write_sint32(4, v)?;
+ }
+ if let Some(v) = self.slice_end {
+ os.write_sint32(5, v)?;
+ }
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -1540,6 +1610,8 @@ impl ::protobuf::Message for EthereumERC7730Path {
self.path.clear();
self.container_path = ::std::option::Option::None;
self.const_value = ::std::option::Option::None;
+ self.slice_start = ::std::option::Option::None;
+ self.slice_end = ::std::option::Option::None;
self.special_fields.clear();
}
@@ -1548,6 +1620,8 @@ impl ::protobuf::Message for EthereumERC7730Path {
path: ::std::vec::Vec::new(),
container_path: ::std::option::Option::None,
const_value: ::std::option::Option::None,
+ slice_start: ::std::option::Option::None,
+ slice_end: ::std::option::Option::None,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -2928,48 +3002,50 @@ static file_descriptor_proto_data: &'static [u8] = b"\
essages.definitions.EthereumABITypeR\x07dynamic\x12J\n\x05tuple\x18\x03\
\x20\x01(\x0b24.hw.trezor.messages.definitions.EthereumABITupleInfoR\x05\
tuple\x12J\n\x05array\x18\x04\x20\x01(\x0b24.hw.trezor.messages.definiti\
- ons.EthereumABIValueInfoR\x05array\"\xaf\x01\n\x13EthereumERC7730Path\
+ ons.EthereumABIValueInfoR\x05array\"\xed\x01\n\x13EthereumERC7730Path\
\x12\x12\n\x04path\x18\x01\x20\x03(\x11R\x04path\x12c\n\x0econtainer_pat\
h\x18\x02\x20\x01(\x0e2<.hw.trezor.messages.definitions.EthereumERC7730C\
ontainerPathR\rcontainerPath\x12\x1f\n\x0bconst_value\x18\x03\x20\x01(\t\
- R\nconstValue\"\xc4\x03\n\x18EthereumERC7730FieldInfo\x12G\n\x04path\x18\
- \x01\x20\x02(\x0b23.hw.trezor.messages.definitions.EthereumERC7730PathR\
- \x04path\x12\x14\n\x05label\x18\x02\x20\x02(\tR\x05label\x12_\n\tformatt\
- er\x18\x03\x20\x02(\x0e2A.hw.trezor.messages.definitions.EthereumERC7730\
- FieldFormatterTypeR\tformatter\x12R\n\ntoken_path\x18\x04\x20\x01(\x0b23\
- .hw.trezor.messages.definitions.EthereumERC7730PathR\ttokenPath\x12\x1c\
- \n\tthreshold\x18\x05\x20\x01(\x0cR\tthreshold\x12\x1a\n\x08decimals\x18\
- \x06\x20\x01(\rR\x08decimals\x12\x12\n\x04base\x18\x07\x20\x01(\tR\x04ba\
- se\x12\x16\n\x06prefix\x18\x08\x20\x01(\x08R\x06prefix\x12.\n\x13const_t\
- oken_address\x18\t\x20\x01(\x0cR\x11constTokenAddress\"\xfa\x02\n\x19Eth\
- ereumDisplayFormatInfo\x12\x19\n\x08chain_id\x18\x01\x20\x02(\x04R\x07ch\
- ainId\x12\x18\n\x07address\x18\x02\x20\x02(\x0cR\x07address\x12\x19\n\
- \x08func_sig\x18\x03\x20\x02(\x0cR\x07funcSig\x12\x16\n\x06intent\x18\
- \x04\x20\x02(\tR\x06intent\x12i\n\x15parameter_definitions\x18\x05\x20\
- \x03(\x0b24.hw.trezor.messages.definitions.EthereumABIValueInfoR\x14para\
- meterDefinitions\x12e\n\x11field_definitions\x18\x06\x20\x03(\x0b28.hw.t\
- rezor.messages.definitions.EthereumERC7730FieldInfoR\x10fieldDefinitions\
- \x12#\n\rprovider_name\x18\x07\x20\x01(\tR\x0cproviderName*i\n\x0eDefini\
- tionType\x12\x14\n\x10ETHEREUM_NETWORK\x10\0\x12\x12\n\x0eETHEREUM_TOKEN\
- \x10\x01\x12\x10\n\x0cSOLANA_TOKEN\x10\x02\x12\x1b\n\x17ETHEREUM_DISPLAY\
- _FORMAT\x10\x03*\xa7\x03\n\x0fEthereumABIType\x12\x0f\n\x0bABI_ADDRESS\
- \x10\0\x12\x0f\n\x0bABI_UINT256\x10\x01\x12\x0f\n\x0bABI_UINT248\x10\x02\
- \x12\x0f\n\x0bABI_UINT160\x10\x03\x12\x0f\n\x0bABI_UINT128\x10\x04\x12\
- \x0f\n\x0bABI_UINT120\x10\x05\x12\x0f\n\x0bABI_UINT112\x10\x06\x12\x0e\n\
- \nABI_UINT96\x10\x07\x12\x0e\n\nABI_UINT72\x10\x08\x12\x0e\n\nABI_UINT64\
- \x10\t\x12\x0e\n\nABI_UINT48\x10\n\x12\x0e\n\nABI_UINT40\x10\x0b\x12\x0e\
- \n\nABI_UINT32\x10\x0c\x12\x0e\n\nABI_UINT24\x10\r\x12\x0e\n\nABI_UINT16\
- \x10\x0e\x12\r\n\tABI_UINT8\x10\x0f\x12\x0c\n\x08ABI_BOOL\x10\x10\x12\
- \x0e\n\nABI_INT160\x10\x11\x12\x0f\n\x0bABI_BYTES32\x10\x14\x12\x0f\n\
- \x0bABI_BYTES16\x10\x15\x12\x0e\n\nABI_BYTES8\x10\x16\x12\x0e\n\nABI_BYT\
- ES4\x10\x17\x12\x0f\n\x0bABI_BYTES20\x10\x18\x12\r\n\tABI_BYTES\x10\x1e\
- \x12\x0e\n\nABI_STRING\x10\x1f*\xac\x01\n!EthereumERC7730FieldFormatterT\
- ype\x12\x1a\n\x16FORMATTER_ADDRESS_NAME\x10\0\x12\x14\n\x10FORMATTER_AMO\
- UNT\x10\x01\x12\x1a\n\x16FORMATTER_TOKEN_AMOUNT\x10\x02\x12\x12\n\x0eFOR\
- MATTER_UNIT\x10\x03\x12\x11\n\rFORMATTER_RAW\x10\x04\x12\x12\n\x0eFORMAT\
- TER_DATE\x10\x05*;\n\x1cEthereumERC7730ContainerPath\x12\x08\n\x04FROM\
- \x10\x01\x12\t\n\x05VALUE\x10\x02\x12\x06\n\x02TO\x10\x03B?\n#com.satosh\
- ilabs.trezor.lib.protobufB\x18TrezorMessageDefinitions\
+ R\nconstValue\x12\x1f\n\x0bslice_start\x18\x04\x20\x01(\x11R\nsliceStart\
+ \x12\x1b\n\tslice_end\x18\x05\x20\x01(\x11R\x08sliceEnd\"\xc4\x03\n\x18E\
+ thereumERC7730FieldInfo\x12G\n\x04path\x18\x01\x20\x02(\x0b23.hw.trezor.\
+ messages.definitions.EthereumERC7730PathR\x04path\x12\x14\n\x05label\x18\
+ \x02\x20\x02(\tR\x05label\x12_\n\tformatter\x18\x03\x20\x02(\x0e2A.hw.tr\
+ ezor.messages.definitions.EthereumERC7730FieldFormatterTypeR\tformatter\
+ \x12R\n\ntoken_path\x18\x04\x20\x01(\x0b23.hw.trezor.messages.definition\
+ s.EthereumERC7730PathR\ttokenPath\x12\x1c\n\tthreshold\x18\x05\x20\x01(\
+ \x0cR\tthreshold\x12\x1a\n\x08decimals\x18\x06\x20\x01(\rR\x08decimals\
+ \x12\x12\n\x04base\x18\x07\x20\x01(\tR\x04base\x12\x16\n\x06prefix\x18\
+ \x08\x20\x01(\x08R\x06prefix\x12.\n\x13const_token_address\x18\t\x20\x01\
+ (\x0cR\x11constTokenAddress\"\xfa\x02\n\x19EthereumDisplayFormatInfo\x12\
+ \x19\n\x08chain_id\x18\x01\x20\x02(\x04R\x07chainId\x12\x18\n\x07address\
+ \x18\x02\x20\x02(\x0cR\x07address\x12\x19\n\x08func_sig\x18\x03\x20\x02(\
+ \x0cR\x07funcSig\x12\x16\n\x06intent\x18\x04\x20\x02(\tR\x06intent\x12i\
+ \n\x15parameter_definitions\x18\x05\x20\x03(\x0b24.hw.trezor.messages.de\
+ finitions.EthereumABIValueInfoR\x14parameterDefinitions\x12e\n\x11field_\
+ definitions\x18\x06\x20\x03(\x0b28.hw.trezor.messages.definitions.Ethere\
+ umERC7730FieldInfoR\x10fieldDefinitions\x12#\n\rprovider_name\x18\x07\
+ \x20\x01(\tR\x0cproviderName*i\n\x0eDefinitionType\x12\x14\n\x10ETHEREUM\
+ _NETWORK\x10\0\x12\x12\n\x0eETHEREUM_TOKEN\x10\x01\x12\x10\n\x0cSOLANA_T\
+ OKEN\x10\x02\x12\x1b\n\x17ETHEREUM_DISPLAY_FORMAT\x10\x03*\xa7\x03\n\x0f\
+ EthereumABIType\x12\x0f\n\x0bABI_ADDRESS\x10\0\x12\x0f\n\x0bABI_UINT256\
+ \x10\x01\x12\x0f\n\x0bABI_UINT248\x10\x02\x12\x0f\n\x0bABI_UINT160\x10\
+ \x03\x12\x0f\n\x0bABI_UINT128\x10\x04\x12\x0f\n\x0bABI_UINT120\x10\x05\
+ \x12\x0f\n\x0bABI_UINT112\x10\x06\x12\x0e\n\nABI_UINT96\x10\x07\x12\x0e\
+ \n\nABI_UINT72\x10\x08\x12\x0e\n\nABI_UINT64\x10\t\x12\x0e\n\nABI_UINT48\
+ \x10\n\x12\x0e\n\nABI_UINT40\x10\x0b\x12\x0e\n\nABI_UINT32\x10\x0c\x12\
+ \x0e\n\nABI_UINT24\x10\r\x12\x0e\n\nABI_UINT16\x10\x0e\x12\r\n\tABI_UINT\
+ 8\x10\x0f\x12\x0c\n\x08ABI_BOOL\x10\x10\x12\x0e\n\nABI_INT160\x10\x11\
+ \x12\x0f\n\x0bABI_BYTES32\x10\x14\x12\x0f\n\x0bABI_BYTES16\x10\x15\x12\
+ \x0e\n\nABI_BYTES8\x10\x16\x12\x0e\n\nABI_BYTES4\x10\x17\x12\x0f\n\x0bAB\
+ I_BYTES20\x10\x18\x12\r\n\tABI_BYTES\x10\x1e\x12\x0e\n\nABI_STRING\x10\
+ \x1f*\xac\x01\n!EthereumERC7730FieldFormatterType\x12\x1a\n\x16FORMATTER\
+ _ADDRESS_NAME\x10\0\x12\x14\n\x10FORMATTER_AMOUNT\x10\x01\x12\x1a\n\x16F\
+ ORMATTER_TOKEN_AMOUNT\x10\x02\x12\x12\n\x0eFORMATTER_UNIT\x10\x03\x12\
+ \x11\n\rFORMATTER_RAW\x10\x04\x12\x12\n\x0eFORMATTER_DATE\x10\x05*;\n\
+ \x1cEthereumERC7730ContainerPath\x12\x08\n\x04FROM\x10\x01\x12\t\n\x05VA\
+ LUE\x10\x02\x12\x06\n\x02TO\x10\x03B?\n#com.satoshilabs.trezor.lib.proto\
+ bufB\x18TrezorMessageDefinitions\
";
/// `FileDescriptorProto` object which was a source for this generated file
Why this scored 31/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.