diff --git a/crates/deckard-browser-bridge/src/lib.rs b/crates/deckard-browser-bridge/src/lib.rs index 16953cf..adf5aaa 100644 --- a/crates/deckard-browser-bridge/src/lib.rs +++ b/crates/deckard-browser-bridge/src/lib.rs @@ -242,16 +242,23 @@ pub async fn serve( anyhow::bail!("browser bridge must bind to loopback (example: 127.0.0.1:8765)"); } let chain_id = wallet.chain_id(); + let socket_display = wallet.socket_path().display().to_string(); + let mock_account = dev_mock_account.clone(); let backend = match dev_mock_account { Some(account) => BridgeBackend::DevMock { account }, None => BridgeBackend::from_env(wallet), }; let bridge = Arc::new(BrowserBridge::new(chain_id, backend)); let listener = TcpListener::bind(bind).await?; - eprintln!( - "Deckard browser bridge listening on http://{bind}/rpc (dev mock via {})", - dev_account_env_name() - ); + match mock_account { + Some(account) => eprintln!( + "Deckard browser bridge listening on http://{bind}/rpc — DEV MOCK account {account} (holds no keys, no daemon)." + ), + None => eprintln!( + "Deckard browser bridge listening on http://{bind}/rpc — dialing signer daemon at {socket_display} (chain {chain_id}).\n\ + If requests fail with a connect error, start `just demo` or `just qa`, unlock the wallet, then retry. The bridge holds no keys." + ), + } loop { let (stream, _) = listener.accept().await?; let bridge = Arc::clone(&bridge); diff --git a/crates/deckard-wallet-client/src/lib.rs b/crates/deckard-wallet-client/src/lib.rs index 400f392..092dd44 100644 --- a/crates/deckard-wallet-client/src/lib.rs +++ b/crates/deckard-wallet-client/src/lib.rs @@ -62,6 +62,11 @@ impl WalletClient { self.config_dir.as_deref() } + /// The signer-daemon socket path this client will dial (for diagnostics/logging). + pub fn socket_path(&self) -> &Path { + self.client.path() + } + pub fn signer_client(&self) -> &SignerClient { &self.client } diff --git a/docs/browser-bridge.md b/docs/browser-bridge.md index bb2218c..0867a11 100644 --- a/docs/browser-bridge.md +++ b/docs/browser-bridge.md @@ -115,15 +115,23 @@ export RPC_URL_SEPOLIA=https://eth-sepolia.g.alchemy.com/v2/ just demo ``` -In another terminal, run the bridge on loopback: +In another terminal, run the bridge against the demo app's daemon: ```sh -export DECKARD_CHAIN_ID=11155111 -cargo run -p deckard-browser-bridge -- --bind 127.0.0.1:8765 +just demo-bridge ``` -The bridge uses the existing Deckard socket path (`DECKARD_SOCKET_PATH` or the default) and calls the -same shared key-less wallet client path that `deckard-mcp address` uses. +`demo-bridge` reuses the demo world's `DECKARD_SOCKET_PATH` and `DECKARD_CHAIN_ID` — the same values +`just demo` launches the app with — so the bridge always dials the daemon the app actually spawned +(`~/.deckard/demo/signerd.sock`) and can't silently fall back to the per-uid default socket. For the +fast-unlock QA world use `just qa-bridge` instead (pair it with `just qa`, unlocked with the +passphrase `deckard-qa`). + +The bridge calls the same shared key-less wallet client path that `deckard-mcp address` uses, and now +logs which socket it dials at startup. If you run it by hand instead of via the recipe, you **must** +set `DECKARD_SOCKET_PATH` (and `DECKARD_CHAIN_ID`) to match the launcher — otherwise it resolves the +per-uid default socket, which `just demo`/`just qa` never use, and reports a misleading "daemon is not +running" error even though the daemon is up on the world socket. ## Load the unpacked extension diff --git a/justfile b/justfile index 43cc38a..4c5c65e 100644 --- a/justfile +++ b/justfile @@ -16,6 +16,13 @@ demo_anvil_port := "8545" demo_fork_block := env_var_or_default("DECKARD_DEMO_FORK_BLOCK", "10822990") demo_fund_eth := "10" +# QA fast-unlock world constants (see the QA section below). Kept as top-level vars so the +# qa recipes and `qa-bridge` resolve identical values — the bridge socket can't drift. +qa_dir := join("/tmp", "deckard-qa") +qa_socket := join(qa_dir, "signerd.sock") +qa_chain_id := "31337" +qa_rpc_url := "http://127.0.0.1:8545" + # List available recipes. default: @just --list @@ -47,19 +54,26 @@ run-tray: # Seal the QA vault into /tmp/deckard-qa (re-run anytime to reset it). qa-vault: - DECKARD_CONFIG_DIR="/tmp/deckard-qa" cargo run -q -p deckard-core --example qa-vault + DECKARD_CONFIG_DIR="{{qa_dir}}" cargo run -q -p deckard-core --example qa-vault # Launch the app against the QA vault, pointed at a local anvil (start `anvil` first # for live balances / send / shield). Run `just qa-vault` once before this. qa: cargo build -p deckard-signerd - DECKARD_CONFIG_DIR="/tmp/deckard-qa" \ - DECKARD_SOCKET_PATH="/tmp/deckard-qa/signerd.sock" \ - DECKARD_CHAIN_ID="31337" \ - DECKARD_RPC_URL="http://127.0.0.1:8545" \ + DECKARD_CONFIG_DIR="{{qa_dir}}" \ + DECKARD_SOCKET_PATH="{{qa_socket}}" \ + DECKARD_CHAIN_ID="{{qa_chain_id}}" \ + DECKARD_RPC_URL="{{qa_rpc_url}}" \ DECKARD_VERIFIED_READS="0" \ cargo run +# Run the key-less browser bridge against the QA fast-unlock app's signer daemon. +# Prereq: `just qa` running in another terminal, unlocked with passphrase `deckard-qa`. +qa-bridge bind="127.0.0.1:8765": + DECKARD_SOCKET_PATH="{{qa_socket}}" \ + DECKARD_CHAIN_ID="{{qa_chain_id}}" \ + cargo run -p deckard-browser-bridge -- --bind "{{bind}}" + # Full walkthrough (onboard -> demo-fund -> shield): CONTRIBUTING "Demo / local-chain dev loop". # Wires an isolated ~/.deckard/demo config dir; verified reads are OFF; Ctrl-C tears anvil down. # Start the demo: a local anvil fork of Sepolia (pinned block) + the Deckard app & daemon. @@ -375,6 +389,14 @@ demo-check: fi exit $RC +# Run the key-less browser bridge against the DEMO app's signer daemon. +# Prereq: `just demo` running in another terminal with the wallet unlocked. +# Reuses the demo world's socket+chain so the bridge can never dial the wrong daemon. +demo-bridge bind="127.0.0.1:8765": + DECKARD_SOCKET_PATH="{{demo_socket}}" \ + DECKARD_CHAIN_ID="{{demo_chain_id}}" \ + cargo run -p deckard-browser-bridge -- --bind "{{bind}}" + # Format + lint the whole workspace (both feature configurations of the app). fmt: cargo fmt