feat: sovereign-mode direct contract writes (CPL-267 Phase 1)#310
Merged
Conversation
Wires the dashboard for direct AccountConfig writes from the user's own wallet when sovereign mode is enabled, preserving the existing API path for everyone else. - Full admin-write ABI bundle + 17 custom errors, ABI drift detection via pinned bytecode hash per (chainId, contractAddress) - Tx lifecycle state machine: preparing → previewing → signing → pending → confirming → confirmed | failed | reorged; revert decoder chains Error(string) → Panic → custom errors → hex fallback and walks the ethers v6 nested error graph - Wallet connect helpers: EOA, EIP-3326 chain switch with EIP-3085 add fallback, accountsChanged / chainChanged listener lifecycle - Required preview+confirm modal before every wallet pop - 14 SDK write methods branched for sovereign mode; usage API keys are generated client-side (contract only stores hash) - Dashboard auto-injects the sovereign lifecycle via Proxy so existing call sites need zero changes Deferred to Phase 1 follow-ups: WalletConnect v2 / Safe integration, Playwright + Synpress E2E harness, live-stack validation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds “sovereign mode” plumbing to the static dashboard + JS SDK so reads can go directly to the AccountConfig contract over RPC and writes can be executed as wallet-signed contract calls with a UI lifecycle (preview → sign → pending/confirming → terminal) and revert decoding.
Changes:
- Introduces wallet connect helpers, tx lifecycle state machine, and a tx preview/confirm modal for wallet-signed writes.
- Extends
LitNodeSimpleApiClientwithmode: 'api'|'sovereign', RPC/contract wiring, ABI drift pinning hooks, and sovereign read/write method branches. - Adds AccountConfig ABI bundles (view subset + full write/errors) and updates the dashboard login UI to toggle modes and preload ethers.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
lit-static/wallet_connect.js |
New EOA wallet-connect + chain switching + listener lifecycle helpers for sovereign mode. |
lit-static/tx_lifecycle.js |
New tx lifecycle runner with state callbacks and revert-data decoding (standard + custom errors). |
lit-static/dapps/dashboard/tx_preview_modal.js |
New required preview+confirm modal that blocks before opening the wallet popup. |
lit-static/dapps/dashboard/index.html |
Loads ethers v6 UMD and adds a sovereign-mode toggle + updated login hint text. |
lit-static/dapps/dashboard/auth.js |
Adds mode persistence + wraps SDK client calls with a Proxy to auto-inject sovereign lifecycle for write methods. |
lit-static/core_sdk.js |
Adds sovereign-mode RPC read path + wallet-signed write path with ABI drift checking and lazy ethers loading. |
lit-static/account_config_view_abi.js |
Adds view-only ABI subset for sovereign reads. |
lit-static/account_config_full_abi.js |
Adds full ABI bundle (views+writes+custom errors) + ABI version and deployment pinning map. |
TODOS.md |
Adds CPL-267 follow-up tasks (cache invalidation, GC, docs, billing notes, etc.). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
8 tasks
- auth.js ensureSovereignSigner: recreate signer after switchChain so ethers BrowserProvider doesn't sign against the pre-switch network - tx_preview_modal.js: resolve promise on #modal-close-btn and overlay backdrop clicks so closing via X no longer hangs the write flow in PREVIEWING - core_sdk.js listActions (sovereign): only treat groupId > 0 as in-group; match server semantics where groupId == 0 is account-level - core_sdk.js module header: remove stale "writes still use HTTP until Phase 1" language; writes are now wallet-signed when a signer is connected - index.html login hint: same stale-copy update - account_config_full_abi.js: freeze empty ACCOUNT_CONFIG_DEPLOYMENTS and add isAbiDriftDevOverrideEnabled() so _verifyAbiIntegrity hard- blocks on unpinned deployments unless window.LIT_ACCOUNT_CONFIG_ALLOW_UNPINNED_DEPLOYMENTS is set - wallet_connect.js switchChain: re-issue wallet_switchEthereumChain after wallet_addEthereumChain and assert final chainId matches target 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
Wires the dashboard for direct AccountConfig writes from the user's own wallet when sovereign mode is enabled, preserving the existing API-server path for everyone else. Phase 1 of CPL-267 per the CEO plan (plan-eng-review cleared).
What ships in this PR:
preparing → previewing → signing → pending → confirming → confirmed | failed | reorgedError(string)→Panic(uint256)→ custom errors → hex fallback; walks the ethers v6 nested error graphmode === 'sovereign'; usage API keys generated client-side (contract only stores hash)getClient()Proxy auto-injects the sovereign lifecycle, zero call-site changes in groups.js / actions.js / wallets.js / keys.jsDeferred to Phase 1 follow-ups (intentional, per plan):
Out of scope (Phase 2+):
newAccountas direct contract writecreateWalletwith server-prepared key +registerWalletDerivationTest plan
NotMasterAccount(…)decodes in the error banner🤖 Generated with Claude Code