Embed per-chain exposure in ledger account status - #13
Merged
Conversation
WalletConnect advertises accounts as `eip155:<chainId>:<address>`, so an
address exposed on Ethereum + Arbitrum + Polygon surfaces as three raw
entries. The flat `accounts` array in get_ledger_status was passing them
through unchanged, which looked like duplicates to agents and forced a
"these two are the same address on different chains" explanation.
- getConnectedAccounts now deduplicates by address (callers that only
need a membership check, like the pre-sign guard, keep working).
- Adds getConnectedAccountsDetailed returning {address, chainIds,
chains} per unique address, preserving first-seen order.
- SessionStatus gains `accountDetails: SessionAccount[]` with the
per-address chain breakdown. `accounts` stays as a deduped flat list
for backward compat with agents that already parse it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This was referenced Apr 27, 2026
Closed
szhygulin
added a commit
that referenced
this pull request
Apr 28, 2026
…501) Inv #12.5 (skill-side, issue #501) marks a curated list of op classes where the second-LLM check is a precondition of `confirmed: true`, not opt-in. The skill-side rule lives in vaultpilot-skill v9+; this PR is the MCP-side scaffold so future hard-trigger op producers can flip a flag at build time and have the existing verification block surface a mandatory ⚠ line. What ships: - New `secondLlmRequired?: boolean` on `UnsignedTx`. Default absent / false. Documentation comment lists today's hard-trigger op classes (all currently deferred or not built): - EIP-7702 setCode (#481) - Permit2 batch grants (#453) - Opaque-facet bridges (#451) - Approval-management N-candidate selection (Inv #13) - Safe enableModule / setGuard / threshold changes - `renderVerificationBlock` reads the flag and emits a single ⚠ line below the hash: ⚠ SECOND-LLM CHECK REQUIRED — call get_verification_artifact(handle) and relay the pasteableBlock to the user BEFORE 'send' (Inv #12.5 hard-trigger op). - 3 tests pinning the behavior: omitted when absent/false, emitted when true, composes cleanly with recipient + tokenClass warnings. What does NOT ship: - No producer wires the flag yet (every hard-trigger op class is itself deferred). The flag is dormant scaffold. - No enforcement layer below the rendered ⚠. The MCP can't tell whether the agent actually ran the second-LLM check — same self- attestation gap as `userDecision: "send"`. Trust note (in the field doc): The flag is a workflow signal, not a cryptographic primitive. Closing the agent-side honesty gap requires infrastructure that doesn't exist today (provider-signed LLM responses, TEE attestation, or zkML proofs of NN inference). Discussed in the PR thread for this issue. Coordinated with skill v9 release (lifts §16 unconditional 7702 refusal + adds Inv #12.5 hard-trigger language); MCP-side `EXPECTED_SKILL_SHA256` bump happens in the skill-coordination PR, not this one. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
eip155:<chainId>:<address>, so one address exposed on Ethereum + Arbitrum + Polygon surfaces as three raw entries.get_ledger_statuswas passing them through unchanged, which looked like duplicates to agents (e.g. "5 entries with 1/4 and 2/5 as duplicates") and forced a manual "same address on different chains" explanation.getConnectedAccounts()now deduplicates by address — callers doing membership checks (pre-sign guard, default-from resolution) keep working but no longer see redundant entries.getConnectedAccountsDetailed()returning{ address, chainIds, chains }per unique address, preserving first-seen order.SessionStatusgainsaccountDetails: SessionAccount[]with the per-address chain breakdown. Each entry mapschainIdsto the server'sSupportedChainnames (ethereum / arbitrum / polygon); unsupported chainIds are preserved inchainIds[]with an emptychains[]slot.accountsstays as a deduped flat list for backward compat with agents that already parse it.Test plan
npm run build— cleannpm test— 209 tests passget_ledger_statuswith a Ledger session exposing the same address on multiple chains; verifyaccountsis deduped andaccountDetailsshows each address with itschainsarray populated.getConnectedAccounts()which now returns deduped addresses).🤖 Generated with Claude Code