# Open Swarm Protocol (Satshoal) — Specification

**Status:** Draft MVP · **Version:** 0.2.0 · **License:** MIT

Three layers, one goal — keep content available with real incentives:

| Layer | Role |
|-------|------|
| **BitTorrent bytes** | Piece hashes, infohash, swarm transfer (incl. WebTorrent / WebRTC) |
| **Lightning money** | Per-piece (and whole-file) payment + retainer (availability) bounties |
| **Nostr gossip** | Listings, seeder ads, bounty notices, optional attestations |

Tagline: *BT bytes + LN money + Nostr gossip.*

---

## 1. Legal model (normative)

This is an **open protocol**. Responsibility is split deliberately:

1. **Clients MAY seed any content their users choose.** A conformant client is a transport + payment tool. It MUST NOT be required by this spec to censor user-selected magnets or payloads.
2. **Hosted indexes and public catalogs SHOULD filter.** Operators that publish discovery lists (web UIs, relay-backed indexes, curated feeds) SHOULD apply a redistributable-license allowlist (or equivalent policy) and SHOULD NOT index clearly infringing commercial media.
3. **Reference demo site catalog** enforces an SPDX allowlist (MIT, Apache-2.0, BSD-*, CC0-1.0, CC-BY-4.0, Unlicense) and never accepts arbitrary user magnets into the server catalog API.
4. Nothing in this document is legal advice. Operators and users remain responsible for local law.

### Suggested allowlist for hosted indexes (SPDX)

`MIT` · `Apache-2.0` · `BSD-2-Clause` · `BSD-3-Clause` · `CC0-1.0` · `CC-BY-4.0` · `Unlicense`

**Local-only magnets:** Clients MAY offer a “seed my magnet” mode that never writes to a hosted catalog. Hosted APIs MUST NOT ingest arbitrary magnets into the public index.

---

## 2. Roles

| Role | Responsibility |
|------|----------------|
| **Leecher** | Discovers listings; pays sats per piece / file; verifies piece hashes |
| **Seeder** | Advertises availability + rate card + Lightning receive address; serves / BT-seeds bytes; answers retention challenges |
| **Retainer funder** | Funds epoch bounties so seeders stay online without continuous leechers |
| **Attestor** (optional) | Observes challenge results; may publish attestation events |

---

## 3. Architecture

```
┌─────────────┐     Nostr kinds 39000–39005      ┌─────────────┐
│   Leecher   │◄──── listings / seeder ads ─────►│   Seeder    │
│  (browser / │                                   │ (browser /  │
│   thick CLI)│── LN invoice (lud16 / BOLT11) ──►│  thick CLI) │
│             │◄──── BT / WebTorrent pieces ─────│             │
└─────────────┘                                   └─────────────┘
       ▲                                                 ▲
       │              optional retainer fund             │
       └─────────────────────┬───────────────────────────┘
                             ▼
                      ┌─────────────┐
                      │  Attestor / │
                      │ index host  │
                      └─────────────┘
```

- **Gossip** never carries file bytes or sats.
- **Invoices** never embed the payload.
- **Pieces** move over BitTorrent / WebTorrent / HTTP webseed after (or alongside) payment according to the client's policy. The MVP demo gates paid HTTP piece delivery on invoice settle; BT swarming is independent bytes transport.

---

## 4. Content addressing (bytes)

Inspired by BitTorrent, simplified for MVP listings:

- **Piece size**: fixed per listing (demo fixtures often use 256 B protocol pieces; BT torrents may use 16 KiB).
- **Piece hash**: SHA-256 of piece bytes, hex.
- **File hash**: SHA-256 of full payload.
- **Protocol infohash**: `SHA-256( concat(piece_hashes) || content_id || license_spdx )` hex.
- **BT infohash**: standard BitTorrent infohash when a `.torrent` / magnet is published.

Listings MAY include `magnet`, `bt_infohash`, `payload_ref`, and/or `webseed` URLs.

---

## 5. Event kinds (draft private range)

Kinds **39000–39010** are experimental. Prefer parameterized replaceable semantics via `d` tag where noted.

| Kind | Name | Replaceable? | Content (JSON) highlights |
|------|------|--------------|---------------------------|
| **39000** | `content_listing` | parameterized (`d` = infohash) | `infohash`, `file_hash`, `piece_hashes[]`, `piece_size`, `license_spdx` (optional on wire; indexes SHOULD require), `payload_ref` / `magnet`, `sats_per_mib`, `lnaddress` |
| **39001** | `seeder_ad` | parameterized (`d` = infohash) | `infohash`, rate card (`sats_per_piece` / `sats_per_mib`), `ln_receive` (lud16), `challenge_endpoint`, optional `bt_infohash`, optional `license_spdx` |
| **39002** | `retainer_bounty` | parameterized (`d` = infohash) | `infohash`, `daily_bounty_sats`, `epoch_hours`, `license_spdx` |
| **39003** | `retainer_fund` | regular | `infohash`, `amount_sats`, `funded_total` |
| **39004** | `challenge_result` | regular | `infohash`, `piece_index`, `expected_hash`, `proof_hash`, `passed`, `payout_sats` |
| **39005** | `attestation` | regular (stub) | Optional third-party confirm of challenge / uptime |

Common tags: `["i", "<infohash>"]`, `["license", "<spdx>"]`, `["d", "<infohash>"]` for parameterized kinds.

Transport: local store and/or public Nostr relays. **This repo does not require announcing to public relays.**

### Seeder ad (39001) — required fields for interoperable clients

| Field | Type | Notes |
|-------|------|-------|
| `infohash` | string | Protocol content id |
| `ln_receive` | lud16 | Where piece / file invoices MUST be created |
| `sats_per_piece` | int ≥ 0 | Rate card |
| `license_spdx` | SPDX | Hosted indexes SHOULD require |
| `bt_infohash` | hex | Optional; when BT / WebTorrent seeding |
| `challenge_endpoint` | URL path | Optional retainer challenge |

---

## 6. Piece invoice / HTLC memo format

### Per-piece (normative)

```
infohash|piece_index|piece_hash|nonce
```

Example:

```
a5359f6d…|0|9c1a…|f3a91b02c8d4e7aa
```

| Field | Meaning |
|-------|---------|
| `infohash` | Protocol content id |
| `piece_index` | Integer piece index |
| `piece_hash` | Expected SHA-256 hex of piece |
| `nonce` | Anti-replay token |

### Whole-file (normative for demo + thick clients)

```
infohash|ALL|remaining_count|file_hash|nonce
```

### Alias (accepted by parsers; future hold-invoice / HTLC binding)

```
infohash|FILE|file_hash|nonce
```

### Settlement policy

- Invoices SHOULD be created to the seeder's **lud16** (`ln_receive` from kind `39001`).
- MVP: **pay → deliver → verify hash → ban on mismatch**.
- Production SHOULD prefer **hold invoices / HTLC-style** patterns so settlement aligns with verifiable delivery (memo binds `piece_hash` / `file_hash`).
- Real LN deployments MAY floor invoice amounts (e.g. ≥ 21 sats) for wallet fee headroom; the memo still describes the logical piece(s).

---

## 7. Piece-pay flow

```
Leecher                         Seeder                      LN
   |                               |                         |
   |  discover listing (Nostr)     |                         |
   |  request piece N              |                         |
   |------------------------------>|                         |
   |                               | create invoice → lud16  |
   |                               | memo = ih|N|hash|nonce  |
   |                               |------------------------>|
   |  pay invoice (WebLN / QR)     |                         |
   |------------------------------------------------------------->|
   |                               | <---- settled ----------|
   |  <---- piece bytes / BT ------|                         |
   |  verify piece hash            |                         |
```

---

## 8. Retainer epoch payout

1. Funder publishes `retainer_bounty` (39002).
2. Funder publishes `retainer_fund` (39003) and credits a fund balance.
3. Each epoch: challenge a random piece hash; on pass, payout seeder (`challenge_result` 39004).

---

## 9. Threat model (summary)

| Threat | Mitigation direction |
|--------|----------------------|
| Sybil seeders | Bonds, rate limits, attestation |
| Fake seed | Piece challenges; leecher hash verify |
| Exit scam | Hold invoices; small pieces; reputation |
| Index abuse | Hosted indexes SHOULD filter; clients MAY still seed user choice |
| Relay spam | Filter by license tag + known publishers |

---

## 10. Out of scope for *hosted demo indexes*

- Accepting arbitrary user magnets into the **server catalog**
- Shipping curated indexes of commercial copyrighted movies/TV/games/warez
- Guaranteeing anonymity or legal advice
- Requiring public Nostr announce (optional only)

Clients implementing the open protocol remain free to offer a **local-only** “seed my magnet” mode that never writes to a hosted catalog.

---

## 11. Package layout (this repo)

```
open_swarm_protocol/   Python helpers (licenses, pieces/memos, kinds, seeder_ad)
SPEC.md                This document
README.md              Quick start + legal split
VERSION / pyproject    0.2.0
```

Reference web demo: `/workspace/open-swarm`  
Thick seeder CLI: `/workspace/open-swarm/thick-client`
