cs-test: registry-compatible runner with nested owner threading - #2
Conversation
Adapts cs-test to the unified clear-signing test runner contract used by
the manuelwedler/clear-signing-erc7730-registry CI:
- New --output/-o <path> flag emits results.json with the runner literal,
implementation id (llbartekll/clear-signing@<version>), and per-case
status (pass/fail/error). Markdown path is unchanged when the flag is
absent.
- Per-case decode/format errors are now captured as error status instead
of aborting the run. Group entries flatten to the parent fields map;
nested calldata emits the recursive {intent, owner, fields} shape.
- DataProviderStub gains nftCollectionNames and blockTimestamps to match
the v2 input format; StubDataProvider resolves both, plus ENS names
from the same address-names map.
- Adds clear_signing::VERSION so the runner can report the library
version it is bound to. Exit code stays 0 in --output mode regardless
of case outcomes per the registry contract.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds decoding for the three legacy forms registry fixtures may carry: 6-field pre-EIP-155 unsigned, 9-field EIP-155 unsigned signing payloads ([..., chainId, 0, 0]), and 9-field signed ([..., v, r, s] with chainId recovered from v). EIP-1559 type-0x02 handling is factored into its own function but unchanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds optional `interpolatedIntent` to the registry-compatible rendered output, populated from `DisplayModel.interpolated_intent`. Omitted (not null) when the descriptor has no template placeholders. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This reverts commit c19a9e6. No registry fixture currently uses legacy transactions (the v2 testsv2/ corpus is EIP-1559 only). The EIP-155 disambiguation between unsigned 9-tuples and signed 9-tuples is untested, and the pre-EIP-155 mainnet default is a footgun. Reintroduce when a real fixture motivates it. The decode_eip1559 internal extraction is reverted along with this; it was bundled into the same commit. Restore as a separate refactor if wanted.
Two related changes to the cs-test test runner so it represents our implementation honestly to the registry and serves the right data to the engine's source-driven address-name resolution. Runner identity. RUNNER_ID is changed from a third-party vendor literal to "@llbartekll/cs-test" so the registry's results.json correctly attributes the harness emitting each row. The docstring referencing a specific upstream fork is dropped. ENS vs local split. The DataProvider trait defines resolve_ens_name and resolve_local_name as semantically distinct lookups, and the engine branches on the field's `sources` array. The stub previously fed both methods from a single addressNames map, so any contact label spuriously satisfied an ENS-sourced field. DataProviderStub now carries a separate ensNames map, and StubDataProvider routes each method to its own map. Adds three unit tests covering ens-only, local-only, and both-populated states. Co-Authored-By: Manuel Wedler <34456797+manuelwedler@users.noreply.github.com>
Nested calldata frames now carry the inner descriptor's metadata.owner.
This closes the parity gap where wallets rendering a nested call had no
way to know whose descriptor produced the inner intent.
Engine. DisplayEntry::Nested gains owner: Option<String>. Calldata
nesting populates it from inner_descriptor.metadata.owner.clone() at the
successful-render site in render_calldata_field; raw/fallback frames
(unresolved callee, unknown selector, depth limit, undecodable inner,
non-bytes calldata) leave it as None. EIP-712 nesting threads it the
same way through the recursive format_calldata call.
cs-test. The registry-compatible results.json now emits the nested
owner via NestedRendered.owner; the empty-string workaround comment is
gone. Pattern matches in compare.rs and the unit test in results.rs are
updated.
Tests. The existing Safe execTransaction nested test asserts the inner
ERC-20 descriptor's owner ("Circle") propagates; the no-inner-descriptor
test asserts raw fallback frames carry None. The three-level userops
nested test asserts owner propagation through EIP-712 → calldata →
calldata.
Downstream. Swift UniFFI bindings are regenerated. Wallet pattern
matches in DisplayModelView, CalldataDiagnostics, and TypedDataDiagnostics
are updated; DisplayModelView renders the inner owner as a small caption
when present. React Native, CLAUDE, and AGENTS docs are updated to
reflect the new field on the nested shape.
Co-Authored-By: Manuel Wedler <34456797+manuelwedler@users.noreply.github.com>
Compare nested expected owners in cs-test, sync React Native bindings with the updated DisplayEntry::Nested layout, and clean generated Swift whitespace. Co-Authored-By: Manuel Wedler <34456797+manuelwedler@users.noreply.github.com>
Rust 1.95 (the version CI now picks up via dtolnay/rust-toolchain@stable) stabilized the manual_is_multiple_of clippy lint. Pre-existing parity checks at five call sites used `% 2 != 0` / `% 2 == 0` patterns, which the new lint rejects under `-D warnings`. Replace each with the explicit `.is_multiple_of(2)` form (stabilized in 1.87, available on our floor toolchain). Sites: - crates/clear-signing/src/uniffi_compat/mod.rs:429 - crates/clear-signing/src/engine.rs:1795 - crates/clear-signing/tests/quickswap_integration.rs:35 - crates/clear-signing/tests/celo_accounts_integration.rs:32 - crates/clear-signing/tests/lifi_integration.rs:35 Pure mechanical fix — no behavior change.
A stray `rust_out` Mach-O binary slipped into the previous commit — it was the output of an offhand `rustc -` probe against the local toolchain. Drop it.
|
thanks, will update the registry PR |
|
One question: why did you revert c19a9e6? I think this made a few tests fail here: manuelwedler/clear-signing-erc7730-registry#2 |
|
Good catch — you're right, and the revert was wrong. My original reasoning ("no fixture exercises legacy txs") was based on the single aave example fixture in #2586 at the time; I didn't account for the bulk migration in manuelwedler/clear-signing-erc7730-registry#2 which ports dozens of real historical fixtures that do use legacy rawTx values. Reapplying your commit in #4 with your co-author attribution preserved. Verified end-to-end against the migrated 1inch AggregationRouterV3 fixture — both cases now run instead of erroring on decode. Sorry for the noise on that one. |
my bad -- restoring it |
Resolve library-side output mismatches surfaced by the upstream registry's v2 test migration (manuelwedler/clear-signing-erc7730-registry #2/#3/#4): - date: RFC-3339 "Z" suffix instead of " UTC" - token amounts: zero renders "0" (not "0.0") - addresses: EIP-55 checksum on the EIP-712 and raw-format paths (calldata parity) - array-of-struct scopes: element-major ordering (fixes wrong field labels) - interpolatedIntent: match {name} templates against #.-prefixed field paths - amount format: render as a native-currency amount - unit base: resolve $.metadata.constants.* references Add cs-test regression fixtures (degate, lido, uniswap, aave, yieldxyz) vendored from the registry. The nested-call case (kiln) is #[ignore]'d: the runner resolves only the outer descriptor, a harness gap rather than an engine bug. The aave Borrow case is dropped (its @.from field is unavailable to the runner). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
cs-testextension that emits a registry-compatibleresults.jsonso the ERC-7730 registry CI can drive our runner alongside other implementations (originally proposed in Add registry-compatible results.json output to cs-test #1).@llbartekll/cs-testand splits the stub's ENS vs local name resolution into separate maps so descriptorsources: [...]arrays are honored correctly.owner: Option<String>toDisplayEntry::Nestedso nested calldata frames carry the inner descriptor'smetadata.owner. Propagated throughengine.rs,eip712.rs, the cs-test renderer, the registry result comparator, the Swift / React Native UniFFI bindings, the iOS wallet, and the integration docs.Commits
c6c6000Add registry-compatible results.json output to cs-test (Manuel)c19a9e6Support legacy transactions in cs-test rawTx decoder (Manuel, reverted below)42298b6Emit interpolatedIntent in cs-test results.json (Manuel)bfc2d44Revert legacy-tx commit (out of scope, no fixture exercises it)02b75cccs-test: emit own runner ID and split ENS vs local stub mapsfe76472Track owner on nested calldata DisplayEntry frames1879f39Fix nested owner comparison and bindingsManuel's original commits keep their SHAs intact. New work is
Co-Authored-By: Manuel Wedler.Test plan
cargo test— 352/352 passingcargo clippy --all-targets -- -D warnings— cleancargo fmt --check— cleancargo test -p clear-signing --features uniffi,github-registry— passingcargo clippy -p clear-signing --all-targets --features uniffi,github-registry -- -D warnings— clean./scripts/generate_uniffi_bindings.sh+./scripts/build-xcframework.sh— cleanxcodebuild -project wallet/Wallet.xcodeproj -scheme Wallet -destination "generic/platform=iOS Simulator" -configuration Debug build— BUILD SUCCEEDEDrunner == "@llbartekll/cs-test",implementation == "llbartekll/clear-signing@0.1.0", 3/3 cases pass with rendered nested owners populatedOut of scope (follow-ups on registry PR #2586)
ensNamesalongsideaddressNamesin the v2 schema; migrate the aave example fixture sososalkin.ethmoves toensNames.runneridentifiers in the spec (currently doc says "Always @ethereum-sourcify/...")..github/actions/run-rust-tests/action.ymlfrom cloning Manuel's fork tocargo install --git https://github.com/llbartekll/clear-signing cs-testagainstmain.Closes #1 (superseded — see the per-fix breakdown in #1 review thread).
🤖 Generated with Claude Code