# Solution: LP-0010 — Shell dApp Integration Proof of Concept **Submitted by:** mmlado ## Summary A web dApp that integrates with the Shell hardware wallet entirely via QR codes — no browser extension, no USB, no Bluetooth. It connects by scanning Shell's export QR, displays derived addresses across all supported derivation paths, and completes a full sign/verify round-trip for both Ethereum and Bitcoin messages. Outbound sign requests now support animated multi-part URs for longer messages, and the Bitcoin response is verified in-browser against the requested message and address before the UI marks it as valid. Confirmed working end-to-end on a real Shell device. ## Repository - **Repo:** https://github.com/mmlado/shell_dapp_prototype - **Live demo:** https://shelldappprototype.vercel.app/ ## Approach The dApp speaks [ERC-4527](https://eips.ethereum.org/EIPS/eip-4527) — a QR-based airgapped signer protocol built on Uniform Resources (UR) and CBOR — directly, without the Keystone SDK. All protocol logic lives in `src/lib/`, a framework-agnostic library structured for future npm extraction. Key design decisions: - **UR decoding and encoding**: a single `URDecoder` instance persists across camera frames to support animated multi-part QRs from Shell, and outbound sign requests are emitted as animated UR sequences when the payload is too large for one frame. The scanner returns `false` to keep running on parse errors so a bad frame doesn't kill the session. - **CBOR**: `cborg` is used for decoding (browser-safe, no Node.js Buffer). For encoding sign requests, a minimal custom encoder (`cbor.ts`) handles CBOR tags — something no browser-compatible encoder supported out of the box. - **source-fingerprint**: Shell validates that the fingerprint in every sign request's keypath matches the inserted card. `parseXpub` extracts it from the scanned UR; both sign request builders include it automatically. - **Browser-safe Bitcoin verification**: the dApp verifies Shell's Bitcoin signature response locally using the returned compressed public key, the requested address, and the signed message. `bip322-js` is kept in test-only coverage to prove compatibility, but is not bundled into the browser runtime. - **Key type detection**: `purpose` and `coinType` from the origin keypath determine which address type to derive. Only key types present in the scanned UR are shown as active in the UI. ## Success Criteria Checklist - [x] **Connects to Shell via QR** — `URDecoder` handles both single-frame and animated multi-part QR codes. No browser extension, native app, or network connection required. - [x] **Displays addresses and public keys across derivation paths** — the UI lists all four key types: EVM (`m/44'/60'/0'/0/0`), Bitcoin legacy P2PKH (`m/44'/0'/0'/0/0`), nested SegWit P2SH-P2WPKH (`m/49'/0'/0'/0/0`), and native SegWit P2WPKH (`m/84'/0'/0'/0/0`). Because a single Shell export QR contains either an Ethereum key or Bitcoin keys — not both simultaneously — only the address types present in the scanned UR are active; the rest are greyed out. - [x] **Message signing with full QR round-trip** — EVM uses EIP-191 `personal_sign` (`ur:eth-sign-request` data-type 3, `ur:eth-signature` response). Bitcoin uses `ur:btc-sign-request` (data-type 1, `btc-message`) with `ur:btc-signature` response. Long sign requests are emitted as animated outbound UR sequences when needed, and the Bitcoin response is verified in-browser before the UI marks it as valid. Both confirmed working on device. - [x] **Fully airgapped** — all data exchange happens through QR codes. No network requests are made after the page loads. - [x] **Developer integration guide and Apache-2.0 license** — see `docs/integration-guide.md`. ## FURPS Self-Assessment ### Functionality Supports all four derivation paths. EVM signing (EIP-191) and Bitcoin message signing are both confirmed working end-to-end against a real Shell device. Outbound sign requests support animated multipart URs, and the Bitcoin signature response is verified locally before the app displays a success state. The protocol library (`src/lib/`) is framework-agnostic and structured for extraction as an npm package. It handles both `ur:crypto-hdkey` (single key) and `ur:crypto-account` (multi-key) connection QRs. ### Usability - Scan Shell's QR → addresses appear immediately, first available key is auto-selected - Clicking a key row selects it (highlighted); inactive keys are visually greyed out - Sign flow: type message → press Sign → QR appears (single-frame or animated multipart depending on payload size) → press "Scan Shell's signature" → camera replaces QR → scan Shell's response → signature displayed with a visible verified/failed status indicator - Supports light and dark theme via `prefers-color-scheme` ### Reliability - Animated QR support: a single `URDecoder` instance persists across frames so all inbound parts are accumulated correctly, and outbound sign requests cycle through all UR fragments until scanned - Scanner keeps running on parse errors — a bad frame or unrecognised QR doesn't kill the session - Bitcoin responses are checked against both the signed message and the expected address before the UI marks them as verified - 56 unit tests covering: CBOR encoder (all branches), address derivation (P2PKH, P2WPKH, P2SH-P2WPKH, EIP-55), xpub parsing (UR and raw base58), key derivation, eth-sign-request structure, btc-sign-request structure, multipart outbound UR generation, browser-safe Bitcoin verification, and BIP-322 compatibility in test-only coverage ### Performance Single-page app, no backend. The production bundle remains browser-safe and no longer pulls `bip322-js` into the client runtime. Address derivation, signature verification, and QR encoding are instantaneous on modern hardware. ### Supportability ``` npm test # 56 tests via Vitest npm run lint # ESLint (0 errors) npx prettier --check "src/**/*.{ts,tsx}" npm run build # production build ``` All library code lives in `src/lib/` with no React dependency, making it straightforward to extract. Each module has a single clear responsibility. See `docs/integration-guide.md` for a full developer walkthrough of the protocol. ## Supporting Materials - [docs/integration-guide.md](docs/integration-guide.md) — developer integration guide covering the full QR exchange format, connection flow, derivation paths, signing protocol, and CBOR implementation notes - [Live demo](https://shelldappprototype.vercel.app/) ## Terms & Conditions By submitting this solution, I confirm that I have read and agree to the [Terms & Conditions](../TERMS.md).