Skip to content

Commit e37459a

Browse files
committed
Moor — a USD₮ wallet with no account to be locked out of
Two stacks that have not been combined in public before, running in one Bare worklet on a phone, from one twelve-word recovery phrase: WDK moves the money, Holepunch moves everything else. Your money, your contact list and your ability to be reached are all derived from those twelve words rather than stored on somebody's server. What works, measured rather than asserted: - An account holding zero wei of ETH sends USD₮0 on Arbitrum One, fee paid in USD₮ through an ERC-4337 bundler and a paymaster in token mode. On chain, from the app, three times. - Contacts sync between an iPhone and an Android emulator on the same seed, through a blind peer that cannot read a byte of them. - A laptop peer the phone had never met asked it for 25 USD₮; the phone showed it in about a second and a half. A stranger is refused before the Noise handshake completes — the contact list is the firewall. - Two people introduce themselves with a QR carrying an address and a HyperDHT peer key. The card renders on a phone and decodes off the screen at 126 characters. What does not: - An account's FIRST send fails with AA20. WDK prices a transfer before it signs the EIP-7702 authorization, and the pricing call omits it, so the bundler simulates an EOA with no code. Upstream, SPEC finding 16. - The camera capture path has never been run — the Simulator has no camera. - Payment requests are verified on iOS only. Eleven tests in lab/ establish every architectural claim before the app relies on it; six run in CI. Nineteen findings, nine filed across three WDK repos. infra/blind-peer publishes the mirror we operate, key included, so the sync half works for anyone who clones this — including apps that are not Moor. Not audited. It holds real money. SECURITY.md says exactly what is at risk.
0 parents  commit e37459a

63 files changed

Lines changed: 24137 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# The point of this file, from lab/README.md:
2+
#
3+
# "If a test starts failing, that's information rather than breakage — check whether the
4+
# finding it encodes has been fixed upstream."
5+
#
6+
# That only means something if the tests actually run. Every check here is hermetic: no
7+
# internet beyond `npm install`, no blind peer, no real money. t3, t8 and t11 stand up their
8+
# own local DHT and pick free ports rather than assuming any.
9+
#
10+
# Deliberately NOT run here, and why:
11+
# t5 fetches delegation bytecode from three public chains
12+
# t6 needs the live blind peer
13+
# t7 needs the public DHT
14+
# t9 needs the public DHT and real NAT traversal
15+
# t10 spends real USD₮ on Arbitrum One
16+
#
17+
# Those four are the ones whose results change when the world changes, which is exactly why
18+
# a green tick here must not be read as "everything still works". See `network-drift`.
19+
20+
name: CI
21+
22+
on:
23+
push:
24+
branches: [main]
25+
pull_request:
26+
schedule:
27+
# Weekly. The WDK packages were shipping every few days when this was written, so the
28+
# interesting failure is a dependency moving underneath us, not a commit breaking things.
29+
- cron: '0 7 * * 1'
30+
workflow_dispatch:
31+
32+
jobs:
33+
lab:
34+
name: Lab — the assumptions the app is built on
35+
runs-on: ubuntu-latest
36+
timeout-minutes: 20
37+
steps:
38+
- uses: actions/checkout@v4
39+
40+
- uses: actions/setup-node@v4
41+
with:
42+
node-version: 20
43+
cache: npm
44+
cache-dependency-path: lab/package-lock.json
45+
46+
- name: Install
47+
working-directory: lab
48+
run: npm ci
49+
50+
- name: t1 — the address book works offline
51+
working-directory: lab
52+
run: npm run t1
53+
54+
- name: t2 — the book is a function of the seed
55+
working-directory: lab
56+
run: npm run t2
57+
58+
- name: t3 — two devices, one seed, nobody in the middle
59+
working-directory: lab
60+
run: npm run t3
61+
62+
- name: t4 — both stacks bundle into one worklet
63+
working-directory: lab
64+
run: npm run t4
65+
66+
- name: t8 — a payment request crosses between strangers
67+
working-directory: lab
68+
run: npm run t8
69+
70+
- name: t11 — the QR exchange
71+
working-directory: lab
72+
run: npm run t11
73+
74+
app:
75+
name: App — typecheck
76+
runs-on: ubuntu-latest
77+
timeout-minutes: 20
78+
steps:
79+
- uses: actions/checkout@v4
80+
81+
- uses: actions/setup-node@v4
82+
with:
83+
node-version: 20
84+
cache: npm
85+
cache-dependency-path: app/package-lock.json
86+
87+
# postinstall runs `wdk-worklet-bundler generate`, which writes the worklet bundle
88+
# App.tsx requires. Without it the typecheck has nothing to resolve.
89+
- name: Install and generate the worklet bundle
90+
working-directory: app
91+
run: npm ci
92+
93+
- name: Typecheck
94+
working-directory: app
95+
run: npx tsc --noEmit
96+
97+
codec:
98+
name: Contact card — the codec both sides share
99+
runs-on: ubuntu-latest
100+
timeout-minutes: 5
101+
steps:
102+
- uses: actions/checkout@v4
103+
104+
- uses: actions/setup-node@v4
105+
with:
106+
node-version: 20
107+
108+
# app/src/wdk/contactCard.mjs has no dependencies at all, so this needs no install and
109+
# gives a fast signal on the one file the app and lab/t11 must agree about.
110+
- name: Round-trip a card
111+
run: |
112+
node --input-type=module -e "
113+
import { encodeCard, decodeCard } from './app/src/wdk/contactCard.mjs'
114+
const address = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
115+
const peerKey = 'a'.repeat(64)
116+
const card = encodeCard({ address, peerKey })
117+
const back = decodeCard(card)
118+
if (back?.address !== address) throw new Error('address did not survive: ' + card)
119+
if (back?.peerKey !== peerKey) throw new Error('peer key did not survive: ' + card)
120+
if (decodeCard(address) !== null) throw new Error('a bare address QR was accepted')
121+
if (card.length > 160) throw new Error('card grew to ' + card.length + ' chars')
122+
console.log('card round-trips, ' + card.length + ' chars')
123+
"

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
node_modules/
2+
.data/
3+
.wdk/
4+
.wdk-bundle/
5+
ios-addons/
6+
*.log
7+
.DS_Store
8+
.env
9+
.env.local
10+
.send-seed

0 commit comments

Comments
 (0)