Skip to content

Commit 8d375ac

Browse files
spec: SolidPay Protocol 1.0 — Editor's Draft, commercial grade
Replace the markdown sketch with a normative, self-contained specification at docs/spec/ (W3C-TR-style HTML, zero deps, dark/light): BCP 14 conformance language with three conformance classes (Node / Client / Auditor); terminology; identity with the normative canonical-spelling rule; the data model (micro-unit amounts, unilateral trustlines, signed single balances); deterministic algorithms (JCS, debt/capacity, route discovery with minimal- hop + full-amount constraints); the five transitions with a precondition/ status/effect table; the transition log with a byte-exact hash definition and an auditor verification algorithm incl. full-replay equivalence; the level-1 did:nostr signature draft (BIP-340 over the JCS bytes, nostr event mapping, open issues); the HTTP API; security and privacy considerations; normative/informative references. Appendix A ships REAL test vectors (JCS, pairKey, micro-units, a three-entry chain with exact hashes and the canonical bytes of entry 3), pinned by test/vectors.test.js so spec and engine cannot drift silently. docs/spec.md becomes a pointer; landing + README link the rendered spec. 19 tests green.
1 parent 5c17f4c commit 8d375ac

5 files changed

Lines changed: 645 additions & 148 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ hash-chained**, and (v1) **signatures via did:nostr**. No blockchain, no
99
token, no consensus, no bank in the middle.
1010

1111
Landing page: <https://jss.live/solidpay/> ·
12-
Spec: [docs/spec.md](docs/spec.md) · Roadmap: [docs/roadmap.md](docs/roadmap.md)
12+
Spec: <https://jss.live/solidpay/docs/spec/> · Roadmap: [docs/roadmap.md](docs/roadmap.md)
1313

1414
## Quickstart
1515

@@ -52,7 +52,7 @@ micro-units; no float drift.
5252
server.js the node: HTTP API + accounts + UI serving (zero deps)
5353
lib/engine.js the ledger engine (pure model + transitions)
5454
lib/ui.js the product UI (one server-rendered document)
55-
docs/spec.md the protocol, including the v1 signature draft
55+
docs/spec/ the protocol spec (Editor's Draft, HTML) + pointer md
5656
docs/roadmap.md v0 testnet → v1 signatures → v2 federation → v3 anchoring
5757
test/ engine units + full-HTTP integration (npm test)
5858
index.html the landing page (GitHub Pages)

docs/spec.md

Lines changed: 17 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,17 @@
1-
# SolidPay protocol — v0 (with the v1 signature draft)
2-
3-
SolidPay is Ryan Fugger's original Ripple (2004) — bilateral credit lines and
4-
payments routed through chains of trust — rebuilt on Solid ideas: every user
5-
is a URI, every transition is hash-chained, and (from v1) every transition is
6-
signed with a key the actor holds. No blockchain, no native token, no global
7-
consensus.
8-
9-
Lineage: [classic.ripplepay.com](https://classic.ripplepay.com/) · Fugger,
10-
*"Money as IOUs in Social Trust Networks"* ·
11-
[webcontracts trustline.v1](https://github.com/webcontracts/webcontracts.github.io/issues/4)
12-
· proven first as the [JSS `ripple` plugin](https://github.com/JavaScriptSolidServer/plugins).
13-
14-
## 1. Identity — every user is a URI
15-
16-
An **agent** is identified by a URI:
17-
18-
- a node-local agent: `https://<node>/u/<name>#me` — MUST dereference to a
19-
profile document (JSON) whose `@id` is the agent URI;
20-
- a Solid WebID: `https://<host>/<pod>/profile/card#me`;
21-
- a DID, e.g. `did:nostr:<hex>` (hex form canonical; npub is display-only).
22-
23-
**Canonical spelling.** One agent MUST have exactly one spelling everywhere in
24-
the ledger. Implementations MUST canonicalize known aliases at every id entry
25-
point; specifically the WebID *document* form `/profile/card.jsonld#me`
26-
normalizes to the *fragment* form `/profile/card#me`. (An identity-keyed graph
27-
silently splits on spelling drift — this rule exists because we hit it live.)
28-
29-
## 2. Amounts
30-
31-
Amounts cross APIs as decimal numbers with at most **6 decimal places**,
32-
`0 < amount ≤ 10^12`. All arithmetic is integer micro-units (amount × 10⁶).
33-
A currency code matches `[A-Z0-9]{1,12}` (uppercased on input) and carries no
34-
built-in meaning — USD, SATS, HRS, BEER are equally valid.
35-
36-
## 3. Trustlines
37-
38-
A **trustline** `(creditor, debtor, currency, limit)` is a unilateral grant:
39-
the creditor permits the debtor to owe them up to `limit` of `currency`.
40-
41-
- Only the creditor MAY create, resize (including to 0 = freeze), or remove
42-
their line. The authenticated actor **is** the creditor — never a parameter.
43-
- Self-trust is invalid.
44-
- Removal MUST be refused (409) while the debtor owes on the line; the IOU
45-
record itself lives in the balance (§4), not the line.
46-
47-
## 4. Balances
48-
49-
One **signed** balance per unordered pair + currency, stored as "lo owes hi"
50-
with `[lo, hi] = sort(a, b)`. The two directions are the same number negated —
51-
two mirrored entries are forbidden (they can desync; one signed number
52-
cannot). A zero balance is removed.
53-
54-
`debt(x→y)` = what x currently owes y (may be negative).
55-
`capacity(x→y) = limit(y→x) − debt(x→y)` — spendable on a hop from x to y.
56-
Negative debt makes owed-to-you credit spendable with **no trustline at all**:
57-
paying back clears debt first ("clearing").
58-
59-
## 5. Payments
60-
61-
A payment `(from, to, currency, amount)`:
62-
63-
1. Find a path from→to where **every** hop has `capacity ≥ amount`
64-
(breadth-first, shortest hops, path length ≤ 8; single path, no partial
65-
fills — a payment either routes whole or fails with "no route").
66-
2. Shift `debt(pᵢ→pᵢ₊₁) += amount` along every hop **atomically**.
67-
68-
Intermediaries need no per-payment consent: each hop consumes credit its next
69-
node already granted. Pre-authorization *is* the routing permission; the only
70-
per-request authorization is the sender's.
71-
72-
**Settle**: the creditor records out-of-band repayment, reducing
73-
`debt(peer→creditor)` by at most its current value. Only the party whose
74-
claim shrinks may record it.
75-
76-
## 6. The transition log
77-
78-
Every state change appends an entry:
79-
80-
```json
81-
{ "seq": 7, "prev": "sha256:…", "ts": "2026-07-29T00:01:57Z",
82-
"actor": "<agent URI>", "type": "send-payment",
83-
"params": { "from": "", "to": "", "currency": "USD",
84-
"amount": 300, "path": ["","",""] },
85-
"hash": "sha256:…" }
86-
```
87-
88-
`hash = sha256( JCS(entry \ {hash, sig}) )` with JCS = RFC 8785 canonical
89-
JSON. `prev` is the previous entry's hash (`null` for seq 1); the newest hash
90-
is the **tip**. Types: `create-trustline`, `update-trustline`,
91-
`remove-trustline`, `send-payment`, `settle`. `GET /api/log/verify` re-derives
92-
the chain; anyone can do the same from `GET /api/log`.
93-
94-
## 7. Signatures — v1 (draft)
95-
96-
v0 authenticates writes with node-local sessions; the node is trusted to
97-
attribute actors honestly. v1 removes that trust:
98-
99-
- Each transition gains `sig`: a BIP340 schnorr signature by the **actor's**
100-
secp256k1 key over the same canonical bytes the hash covers
101-
(`JCS(entry \ {hash, sig})`).
102-
- The actor URI binds to the key via `did:nostr:<hex>` directly, or via a
103-
verification method in the agent's profile document / WebID card.
104-
- A node MUST reject a transition whose signature does not verify against the
105-
actor's key — including its own; the node becomes a coordinator, not an
106-
authority. Anyone replaying the log re-verifies every signature.
107-
- A signed transition is deliberately shaped like a nostr event (pubkey,
108-
created_at, kind, content, sig) so the ledger can be carried by nostr
109-
infrastructure — which is the on-ramp to federation (v2): cross-node routes
110-
as signed, relayable, independently verifiable events.
111-
112-
## 8. HTTP API (v0)
113-
114-
```
115-
POST /api/register {username,password} → 201 {agent, token}
116-
POST /api/login {username,password} → 200 {agent, token}
117-
GET /api/whoami → {agent|null}
118-
GET /u/<name> → profile document
119-
GET /api/graph → {trustlines[], balances[], seq, tip}
120-
GET /api/balances?agent=<uri> → {agent, positions[], net{}}
121-
GET /api/path?from&to&currency&amount → {path[], hops} | 404
122-
POST /api/trustlines {peer,currency,limit} → 201/200 [creditor]
123-
POST /api/trustlines/remove {peer,currency} → 200 | 409 [creditor]
124-
POST /api/payments {to,currency,amount} → 200 | 404 [sender]
125-
POST /api/settle {peer,currency,amount} → 200 | 409 [creditor]
126-
GET /api/log?limit=N → {seq, tip, entries[]}
127-
GET /api/log/verify → {valid, seq, tip}
128-
```
129-
130-
Writes are `Authorization: Bearer` (stateless HMAC in v0; signature-bearing
131-
bodies in v1 make the bearer optional). Errors are `{error}` with honest
132-
status codes. The graph is public in v0 — per-agent visibility is an open
133-
design question tracked in the roadmap.
134-
135-
## 9. Known limits of v0
136-
137-
- **Single node.** Atomicity comes free in-process; cross-node payment is the
138-
federation problem (v2) — hold/commit or hashlocks, not hand-waving.
139-
- **Public graph.** Fugger's RipplePay showed users only their own lines;
140-
a privacy model (per-agent views, maybe pod-mirrored statements) is v1+.
141-
- **Log growth.** The state file rewrites whole; an append-log is the obvious
142-
fix when it matters.
1+
# SolidPay Protocol 1.0
2+
3+
The normative specification lives at **[docs/spec/](https://jss.live/solidpay/docs/spec/)**
4+
([source](spec/index.html)) — an Editor's Draft covering conformance classes
5+
(Node / Client / Auditor), identity and canonical agent spelling, the data
6+
model (micro-unit amounts, unilateral trustlines, signed single balances),
7+
deterministic algorithms (JCS, capacity, route discovery), the five
8+
transitions with error semantics, the hash-chained transition log and its
9+
verification algorithm, the level-1 did:nostr signature draft, the HTTP API,
10+
security and privacy considerations, and **Appendix A test vectors** that the
11+
reference implementation pins in `test/vectors.test.js`.
12+
13+
Quick links:
14+
15+
- [Rendered spec](https://jss.live/solidpay/docs/spec/)
16+
- [Roadmap](roadmap.md)
17+
- [Reference implementation](https://github.com/JavaScriptSolidServer/solidpay)

0 commit comments

Comments
 (0)