mirror of
https://github.com/logos-co/lambda-prize.git
synced 2026-08-27 17:41:17 +00:00
Solution: LP-0010 — Shell dApp Integration Proof of Concept
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# 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. 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**: a single `URDecoder` instance persists across camera frames to support animated multi-part QRs. 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.
|
||||
- **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 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. 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.
|
||||
|
||||
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 → press "Scan Shell's signature" → camera replaces QR → scan Shell's response → signature displayed
|
||||
- Supports light and dark theme via `prefers-color-scheme`
|
||||
|
||||
### Reliability
|
||||
|
||||
- Animated QR support: a single `URDecoder` instance persists across frames so all parts are accumulated correctly
|
||||
- Scanner keeps running on parse errors — a bad frame or unrecognised QR doesn't kill the session
|
||||
- 44 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
|
||||
|
||||
### Performance
|
||||
|
||||
Single-page app, no backend. The build is ~660 KB gzipped (~220 KB) — dominated by `@ngraveio/bc-ur` and `@scure/bip32`. Address derivation and QR encoding are instantaneous on modern hardware.
|
||||
|
||||
### Supportability
|
||||
|
||||
```
|
||||
npm test # 44 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).
|
||||
Reference in New Issue
Block a user