Skip to content

feat(v2): support map references in field parameters - #351

Merged
ckorchane-ledger merged 6 commits into
mainfrom
feat/v2-map-references
Oct 9, 2026
Merged

ckorchane-ledger merged 6 commits into
mainfrom
feat/v2-map-references

Conversation

@paoun-ledger

@paoun-ledger paoun-ledger commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Map references ({"map": "$.metadata.maps.X", "keyPath": "..."}) in v2 field parameters were previously dropped with an "Unresolved map reference" warning. They are now resolved:

  • Constant key (keyPath is a $.… descriptor path): the map value is selected at conversion time and emitted as a plain constant. Hex keys (addresses) match case-insensitively.
  • Data / container key (#.…, @.…): kept as a new ResolvedValueMap (key path + encoded constant values) in the resolved model. Supported on token, chainId (tokenAmount / tokenTicker), senderAddress (addressName / interoperableAddressName), callee, selector, amount, spender (calldata) and collection (nftName).
  • Deployment validation: maps keyed on @.chainId or @.to are checked against every deployment, and a missing value is an error (the spec says a wallet MUST treat the descriptor as invalid in that case).
  • Calldata descriptors: generated per deployment, so @.chainId / @.to maps resolve to constants; other keys are emitted as device side maps (MAP_REF + MAP_ENTRY). PARAM_TOKEN_AMOUNT / PARAM_TOKEN cannot encode a chain id: a tokenAmount chainId (plain or from a map) is ignored with a warning when it may differ from the deployment chain (tokenTicker already warned whenever a chain id is set).
  • Map validation: hex keys are matched case-insensitively, so maps with keys only differing by case are rejected. Hex values must have an even number of digits.
  • Legacy EIP-712: map lookups are reported as unsupported.
  • Lint: map key paths are included in v2 schema path checks.

Test plan

  • New resolved-conversion fixtures: data key, constant key, missing key (token amount + other parameters)
  • New calldata conversion tests for deployment-keyed maps
  • Regression tests for review findings: map keys linter on fixed point ABI types, odd-length hex map values, keys only differing by case, ignored tokenAmount chainId warning
  • prek run --all-files (ruff, mypy, bandit, codespell, …) passes
  • pytest tests: 327 passed, 2308 skipped (registry integration tests, not run)
  • Docs build (not run locally)

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Failed or unsupported map lookups can still produce incomplete descriptors, and map-value validation needs correction.

Review effort: Balanced
Findings: 2 High severity · 3 Medium severity

Open (5)
What changed in this PR

Adds map-reference support to v2 field parameters across descriptor resolution and downstream conversion.

Changes:

  • Resolves constant keys and preserves runtime map lookups.
  • Adds deployment validation and map-key path linting.
  • Extends calldata conversion, legacy diagnostics, and conversion tests.
File Description
tests/​v2/​convert/​resolved/​test_convert_input_to_resolved.py Registers map conversion cases.
tests/​v2/​convert/​resolved/​data/​token_amount_with_map_resolved.json Expected runtime token map.
tests/​v2/​convert/​resolved/​data/​token_amount_with_map_missing_key_input.json Missing deployment-key fixture.
tests/​v2/​convert/​resolved/​data/​token_amount_with_map_input.json Deployment-keyed token fixture.
tests/​v2/​convert/​resolved/​data/​token_amount_with_map_constant_key_resolved.json Expected constant token lookup.
tests/​v2/​convert/​resolved/​data/​token_amount_with_map_constant_key_input.json Constant-key token fixture.
tests/​v2/​convert/​resolved/​data/​maps_in_parameters_resolved.json Expected parameter maps.
tests/​v2/​convert/​resolved/​data/​maps_in_parameters_missing_key_input.json Missing callee-key fixture.
tests/​v2/​convert/​resolved/​data/​maps_in_parameters_input.json Multiple mapped parameters.
tests/​v2/​convert/​resolved/​data/​maps_in_parameters_constant_key_resolved.json Expected constant parameters.
tests/​v2/​convert/​resolved/​data/​maps_in_parameters_constant_key_input.json Constant-key parameter fixtures.
tests/​v2/​convert/​calldata/​test_convert_fields.py Tests deployment lookups and unsupported keys.
src/​erc7730/​model/​resolved/​v2/​display.py Adds resolved map values.
src/​erc7730/​lint/​v2/​path_schemas.py Includes map-key paths.
src/​erc7730/​convert/​resolved/​v2/​values.py Implements map resolution and lookup.
src/​erc7730/​convert/​resolved/​v2/​parameters.py Resolves mapped field parameters.
src/​erc7730/​convert/​resolved/​v2/​convert_erc7730_input_to_resolved.py Validates deployment map coverage.
src/​erc7730/​convert/​ledger/​eip712/​convert_erc7730_v2_to_eip712.py Adds unsupported-map diagnostics.
src/​erc7730/​convert/​calldata/​convert_erc7730_v2_input_to_calldata.py Resolves deployment-specific map values.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/erc7730/convert/resolved/v2/parameters.py Outdated
Comment thread src/erc7730/convert/ledger/eip712/convert_erc7730_v2_to_eip712.py Outdated
Comment thread src/erc7730/convert/resolved/v2/values.py
Comment thread src/erc7730/convert/resolved/v2/values.py Outdated
Map references ({"map": ..., "keyPath": ...}) in v2 field parameters were
dropped with a warning. They are now resolved:

- a constant key ($.…) selects the map value at conversion time
- a data/container key is kept as a ResolvedValueMap lookup in the
  resolved model (token, chainId, senderAddress, callee, selector, amount,
  spender, collection)
- maps keyed on @.chainId / @.to are checked against every deployment, and
  resolved per deployment when generating calldata descriptors
- legacy EIP-712 conversion reports map lookups as unsupported

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/erc7730/convert/resolved/v2/values.py Outdated
Map lookups keyed on calldata (#.…) or on @.from / @.value were rejected
by the calldata converter. They are now looked up by the device, as
specified in app-ethereum doc/tlv_structs.md#map_entry:

- add a MAP_REF value source (VALUE tag 0x06: version, map id, key as a
  nested VALUE with a data or container path)
- emit one MAP_ENTRY instruction per map key (version 0x01, chain id,
  contract address, selector, id, key, value) in a new "maps" list next
  to "enums", for CAL to sign with the calldata key and serve
- encode keys exactly as the device reads them: 32 bytes ABI word for
  static values, raw content for dynamic ones, the slice for sliced
  paths, 20 bytes for @.from, 32 bytes for @.value
- allocate map ids per descriptor, sharing them between lookups with the
  same key and value encodings
- reject keys / values the device cannot store or match (empty or over
  32 bytes, not fitting the key type, duplicate encodings, multi-valued
  key paths, key VALUE over 48 bytes)
- keep folding @.chainId / @.to maps into constants, as a descriptor is
  bound to a single deployment
- keep the referenced map path in ResolvedValueMap to identify entries

Note MAP_ENTRY version is 0x01 as enforced by map_entry.c, the doc still
states 0x0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved lookup ambiguity, dropped chain metadata, and validation and error-handling regressions affect correctness.

Review effort: Balanced
Findings: 4 Medium severity

Open (4)
Resolved since last review (1)

Comment thread src/erc7730/convert/calldata/v1/map.py Outdated
Comment thread src/erc7730/convert/resolved/v2/values.py
Comment thread src/erc7730/lint/v2/lint_validate_map_keys.py
- map keys linter: only build the ABI tree for formats with map lookups keyed
  on transaction data, so formats using fixed point types still lint
- reject hex constants with an odd number of digits, which could not be
  decoded when serializing map values and constants
- reject maps with hex keys only differing by case, since hex keys are matched
  case-insensitively
- calldata: warn when a tokenAmount chainId differs from the deployment chain,
  as PARAM_TOKEN_AMOUNT cannot encode it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Map-key linting rejects valid descriptors with unrelated fixed-point arguments and aborts subsequent checks.

Review effort: Balanced
Findings: None

Resolved since last review (4)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Avoid linter failure on maps with unrelated fixed-point arguments

src/​erc7730/​lint/​v2/​lint_validate_map_keys.py:52

A format such as deposit(uint256 assets, uint32 marketId, fixed128x18 rate) fails linting when a token map uses #.marketId or even @.from. function_to_abi_tree() visits every argument and raises NotImplementedError for fixed/ufixed (convert/calldata/v1/abi.py:189–190). The exception escapes this linter, marks the descriptor as invalid, and skips subsequent checks, although the fixed-point argument is unrelated to the lookup. Avoid ABI-tree construction for container keys and handle unsupported unrelated ABI types without aborting linting. Extend the fixed-point regression test to cover both data-keyed and container-keyed maps; it currently covers only formats without maps.

- reject a tokenAmount chainId that differs from the deployment chain
  (plain value or map lookup): PARAM_TOKEN_AMOUNT cannot encode it, and
  the device would display the token with a wrong ticker and decimals
- reuse the values encoded at resolution for MAP_ENTRY structs
- share is_deployment_key between the converter and the map keys linter
- use a single pattern to reject optional parameters failing to convert

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Map-key linting rejects valid fixed-point signatures, and token chain-path validation remains incomplete.

0 open findings

Previously missed (2)

In code that hasn't changed since last review

Medium severity chainIdPath bypasses chain consistency validation

src/​erc7730/​convert/​calldata/​convert_erc7730_v2_input_to_calldata.py:952

The new chain check ignores chainIdPath. A chain-1 deployment using chainIdPath: "#.targetChainId" still produces a tokenAmount descriptor when the transaction selects chain 8453. The device then resolves ticker and decimals on chain 1, potentially displaying an incorrect amount. Reject chain paths that cannot be proven equivalent to @.chainId, just as this check rejects unsupported chainId values.

Medium severity Unsupported ABI argument blocks token map validation

src/​erc7730/​lint/​v2/​lint_validate_map_keys.py:52

A valid signature such as deposit(uint256 assets, fixed128x18 rate) with a token map keyed on @.from fails here: function_to_abi_tree visits every argument and raises NotImplementedError for rate. This prevents map validation and subsequent linters from running, even though a container key needs no ABI. Validate container keys without building the tree, and avoid making unrelated unsupported ABI types fatal for data-key validation. Add a regression test combining a map lookup with an unrelated fixed-point argument.

🧠 Review effort: Balanced

@ckorchane-ledger ckorchane-ledger left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to handle 2 error cases

Comment thread src/erc7730/convert/calldata/convert_erc7730_v2_input_to_calldata.py Outdated
Comment thread src/erc7730/convert/calldata/convert_erc7730_v2_input_to_calldata.py Outdated
@ckorchane-ledger
ckorchane-ledger merged commit 30626f8 into main Oct 9, 2026
13 checks passed
@ckorchane-ledger
ckorchane-ledger deleted the feat/v2-map-references branch October 9, 2026 05:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants