diff --git a/keepkeylib/erc7730_compiler.py b/keepkeylib/erc7730_compiler.py index b62cdb70..25d2a515 100644 --- a/keepkeylib/erc7730_compiler.py +++ b/keepkeylib/erc7730_compiler.py @@ -605,8 +605,12 @@ def intern_path(steps): arguments.append((2, 1, literal_path)) elif isinstance(token, str): arguments.append((2, 1, intern_path(_resolve_path(root, token)))) - else: + elif token is not None: raise ValueError("tokenAmount requires token or tokenPath") + elif any(key in params for key in ( + "threshold", "message", "chainId", "chainIdPath")): + raise ValueError( + "unknown token amount cannot use token metadata parameters") if "threshold" in params: threshold = descriptor_value(params["threshold"]) if isinstance(threshold, str) and threshold.startswith("0x"): @@ -627,7 +631,7 @@ def intern_path(steps): raise ValueError("invalid tokenAmount chainId") aliases = params.get("nativeCurrencyAddress", ()) aliases = descriptor_value(aliases) - if aliases: + if aliases and token is not None: if isinstance(aliases, str): aliases = [aliases] references = [] diff --git a/tests/test_erc7730_compiler.py b/tests/test_erc7730_compiler.py index f108eff0..a8544e64 100644 --- a/tests/test_erc7730_compiler.py +++ b/tests/test_erc7730_compiler.py @@ -269,6 +269,28 @@ def test_compiles_recursive_array_iteration_frames(): subprocess.check_call([validator, output.name]) +def test_token_amount_without_token_uses_firmware_raw_fallback(): + descriptor = {"display": {"formats": { + "quote(uint256 amount)": { + "intent": "Review quote", + "fields": [{"path": "amount", "label": "Unknown token amount", + "format": "tokenAmount"}], + } + }}} + compiled = compile_calldata( + descriptor, "quote(uint256 amount)", 1, + "0x1111111111111111111111111111111111111111") + formatter = _sections(compiled)[6] + assert formatter[2:5] == bytes([3, 0, 1]) + assert formatter[5:9] == bytes([1, 1, 0, 0]) + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + def test_compiles_typed_if_not_in_and_must_match_conditions(): descriptor = {"display": {"formats": { "guard(uint256 mode,address recipient)": {