Metadata-Version: 2.4
Name: loopmarket
Version: 0.14.0
Summary: Universal combinatorial marketplace: uniform offers over an OntoDAG catalogue, a versioned offer book on recordstore/Swarm, and solver agents hunting profitable loops
License: BSD-3-Clause
Project-URL: Homepage, https://github.com/petfold/loopmarket
Project-URL: Repository, https://github.com/petfold/loopmarket
Project-URL: Issues, https://github.com/petfold/loopmarket/issues
Keywords: marketplace,combinatorial-exchange,ontology,dag,subsumption,swarm,web3,decentralized,solver,negative-cycle,barter,mutual-credit,coincidence-of-wants
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ontodag>=0.30.0
Requires-Dist: recordstore>=0.21.0
Provides-Extra: swarm
Requires-Dist: recordstore[bee,feeds]>=0.21.0; extra == "swarm"
Provides-Extra: sig
Requires-Dist: eth-keys; extra == "sig"
Requires-Dist: eth-hash[pycryptodome]; extra == "sig"
Requires-Dist: coincurve; extra == "sig"
Requires-Dist: cryptography; extra == "sig"
Provides-Extra: chain
Requires-Dist: web3>=6; extra == "chain"
Provides-Extra: evm
Requires-Dist: web3>=6; extra == "evm"
Requires-Dist: py-solc-x; extra == "evm"
Requires-Dist: eth-tester[py-evm]; extra == "evm"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Dynamic: license-file

# loopmarket

[![license](https://img.shields.io/badge/license-BSD--3--Clause-blue)](LICENSE)

A universal combinatorial marketplace over the
[ontodag](https://github.com/petfold/ontodag) /
[recordstore](https://github.com/petfold/recordstore) /
[Ethereum Swarm](https://www.ethswarm.org/) stack.

Every economic intention is one uniform, content-addressed **offer** — a
thing described as a conjunction of OntoDAG categories (where and when it
changes hands are terms among them), priced on the maker's **personal
scale** (a personal
numeraire; the record encoding calls it the maker's personal token). A
distributed, versioned **offer book** holds them (recordstore keyspace;
Swarm-backed via `BeeBytesStore` + a signed `SwarmFeedPointer`). Competing
**solver agents** hunt profitable **loops** — cycles whose exchange-rate
product exceeds one, i.e. negative cycles under −log weights — and a
**clearing** layer re-verifies every leg from scratch and commits the
whole loop atomically.

loopmarket is open source on the internet with no organisation behind
it. Compliance with any jurisdiction's law is entirely the responsibility
of the makers who use it; the protocol neither enforces nor designs
around it. What the design holds itself to is good commercial practice:
the solutions merchants, private courts and mutuals converged on because
they were more efficient, safer and produced fewer conflicts
(`docs/plans/commercial-practice-review.md`).

```console
$ odag -f market.od put piano-lesson music-lesson   # the catalogue is ontodag's
$ loop set catalogue market.od
$ loop set maker amara; loop place home 46.05,14.50,5km; loop set terms home
$ loop give piano-lesson 100                # I give this, priced on my scale
$ loop want produce local weekly 104        # I want this, priced on my scale
$ loop loops && loop clearing               # hunt profitable loops; run the clearing house
```

`loop` is the command line (`pip install loopmarket`): ontodag's grammar
plus two conventions — a bare number first is the quantity, last is the
price — and `+` between the parts of a want that must clear together;
every term the catalogue's (your own places stay private and publish as
their cell), an omitted price your last unit price, and nothing published
before the fully resolved offer is shown.
Type `loop` alone for a prompt, pipe it a script for a batch. The same in
Python:

```python
from recordstore import MemoryBytesStore, RecordStore
from loopmarket import (Ontology, OfferRegistry, MockClearing,
                        SolverAgent, Thing, give, want, ...)

ontology = Ontology().load({"produce": [], "vegetable-box": ["produce"], ...})
registry = OfferRegistry(RecordStore(MemoryBytesStore()))
registry.publish_many([...])          # gives and wants, one uniform form
registry.commit()

agent = SolverAgent(registry, ontology, MockClearing(registry, ontology))
agent.step()                          # snapshot → match → candidates → select → propose; clearing re-verifies
```

## Try it

```bash
pip install -e ".[test]"              # (--break-system-packages or a venv)
python3 -m pytest tests/ -v           # 305 tests (three need a live Bee node, sixty the evm extra, one swarmfs — skipped per test without them)
LOOP_HOME=$(mktemp -d) loop --catalogue examples/triangle.od < examples/triangle.loop   # P0 as a script
PYTHONPATH=src python3 examples/demo_triangle.py     # the same, through the API
PYTHONPATH=src python3 examples/demo_federation.py   # P1: books, fold, forgery, follower
```

Extras, when you need them: `.[sig]` (offer signatures, sealed handoffs,
notices and cases), `.[chain]` (the announcements, beats and escrow on
Gnosis), `.[evm]` (compiling the contracts and running them on a local
EVM), `.[swarm]` (a live Bee node).

The script publishes the smallest nontrivial book — a piano teacher, a
market gardener and a bicycle mechanic, no pair of whom can trade — and
`loops && clearing` finds, verifies and clears the triangle at a 12% surplus:
fifteen lines of `set maker`, `give piano-lesson amara_flat 100`,
`want produce local weekly amara_flat 104`, ...
`examples/delivery.loop` clears a *circulation*: the grocer's box at the
shop plus the courier's run to the door as one composed leg (2026-09-13).
The triangle script runs unchanged with the book on Swarm
(`loop -f swarm:TOPIC ...`; 0.3.0 live-checked 2026-09-12 on a Bee 2.8.2
light node: published, solved and cleared in 1m51s with the same `loop_id`
the in-memory run gives, a fresh session reading the six fills back in
11s). The federation demo runs per-maker books on their own feeds, two
aggregators folding to byte-identical manifests, a censoring aggregator
convicted by absence proofs, a forged offer dying at the fold, a
tombstoned offer staying closed, clearing provably based on the fold, and
a follower reading it all back — in memory by default, live against a Bee
node when `BEE_API` and `BEE_BATCH` are set (0.3.0 live, with ontodag's
core pack: 4m25s, every check true). New here? Start with the
**[User Guide](docs/USER-GUIDE.md)** (a tutorial at the command line,
with the API alongside), then the **[Reference Manual](docs/REFERENCE.md)**
(commands, settings, API, record formats, invariants). `loop help` is the
one-screen version; the design record with its reasons is
[`docs/plans/cli.md`](docs/plans/cli.md).

Candidate generation can also run through ontodag's **parametric
dimensions**: `DimensionIndex` files gives under exactly the terms they
carry (`geo(u24)`, `ljubljana`, `time(...)`, `from(my_home)` — cells,
places, regions and floors, ordered by the graph), and
`candidate_matches_indexed` asks **one** ontodag `get` per want — the
want's categories as the query, items only; where and when are the exact
check's, since a give that contains the want's place sits above it —
provably the same matches as the exhaustive baseline
(the recall test enforces set-equality), with far fewer exact checks. The
index is a derived, per-solver copy; the shared catalogue and its pinned
roots never move because of it. Swap the in-memory store for
`recordstore.swarm_store("offers", signer=...)` (extra:
`pip install -e ".[swarm]"`, plus a Bee node and a postage batch) and the
same code runs with the book on Swarm.

## What is built, and what is designed

**Built (as of 0.14.0):** the full pipeline above runs
in memory — and, since 2026-09-12, from the command line (`loop`) — and since 2026-08-01 also end-to-end on a real Gnosis-mainnet
Bee node — catalogue and book on Swarm, book head in a signed feed, fills
atomic (the gated `tests/test_swarm_book.py`). Since 2026-08-21 the
federation layer runs too — in memory *and* live (the gated
`tests/test_swarm_federation.py`, 96.5s on a Bee 2.8.1 node): per-maker
books under their own feeds and signers, an `Aggregator` folding them
under the U8 admission rules into a three-root manifest published on its
own feed, withdrawal tombstones, and a scorched-earth follower
reconstructing the cleared world from (address, topic) alone. Since
2026-09-04 the federation demo adopts ontodag's `core` pack as the
catalogue and includes a censoring aggregator: `audit_manifest` convicts
it from its own manifest with absence proofs, and a solver folding the
announced maker books itself recovers the honest fold (T14). Since
2026-09-14 discovery is one registry event on the chain Swarm settles on
(`LoopBookRegistry`, deployed on Gnosis): `loop announce` says "my book is
here", and every session with the `registry` setting folds the announced
books itself under the admission rules — the read path needs no
aggregator to trust; the v4 record carries exact rationals (U9), a
thing's `step` and `min`, wants of several parts, fills with the
quantity taken, partial fills of divisible gives and aggregation by
quantity. Since 2026-09-15 clearing reaches the chain: recordstore's trie
proofs verified on the EVM (`contracts/TrieProofVerifier.sol`), the
structural half of a leg verified from the anchored root and the record
bytes (`LoopVerifier.sol`), and the optimistic beat (`BeatClearing.sol`,
deployed on Gnosis) — one outcome per beat with a bond, a challenge
window, fills recorded on chain at finalization — posted to from
`loop propose` and, since 2026-09-18, challenged from `loop challenge`
(the record rebuilt from the submitter's book, the contract's verdict
asked for free, sent only where it convicts); the semantic half stays
optimistic with an arbiter hook. Since 2026-09-18 (0.11.0) the chain
verifies books on Swarm under their own BMT addressing
(`SwarmAddress.sol`), composed wants leg by leg, and — in front of the
beat — the sealed-proposal auction (`SealedBeat.sol`, `loop commit` /
`reveal` / `outcome`: numeraire-free scoring, the baseline as reserve
bid, the fairness filter); the baseline selects among every simple cycle
with one packer (`selection.py`); and guarantees are **admissibility by
declaration** (the v5 record): a maker's neutral point, cancellation
ladder and accepted assets on its own scale, a giver's deposit reserved
per fill — gated in matching, checked on chain, and since 2026-09-19
*held*: the crypto escrow (`LoopEscrow.sol`, deployed on Gnosis, a smart
contract as a maker) holds the deposit, the gate counts a bond only up
to what the contract holds, `loop finalize` reserves the share per fill,
and every undisputed case settles by timeout or the parties' own acts —
a contested claim is factbond's. Since 2026-09-28/29 (the v6 record,
released in 0.13.0) a want can require **credentials** of the other side
— statements presented in its book, issued under accredited registers,
checked by the counterparty gate in seven steps, the registers' roots a
checked sequence (each keeps every earlier revocation: recordstore 0.21.0's
extension proofs) — an offer can be held for someone by an **option**
(`loop option`, `exercise`, `holds`), one particular thing is named by
**`item(h)`** with one open claim per maker, and cover and inspections
compose with the thing as argument-only operators; the escrow releases a
held reservation only by a ruling or both parties (redeployed on Gnosis
the same day), and the clearing contracts verify holds, item claims and
statements on chain (`StatementVerifier` beside the leg verifier,
redeployed the same day — a beat pinning a register root after a
revocation is convicted by challenge). A maker may accept arbitrators by
property (accredited under a named root, a deposit at stake, a clean
record), and since 2026-10-01 the default form is the simplest one: **one
arbitrator both sides accept, whose ruling is final** — the case (claim,
answer, reasons) sealed through the books, the money moved by the escrow,
and a personal view of arbitrators from the escrow's log (`loop claim`,
`answer`, `hold`, `rule`, `arbitrators`; live on Gnosis the same day).
Alpha; interfaces will move.

**Designed (2026-08-07):** most of what loopmarket *is* now lives as a
decided, research-grounded plan corpus under `docs/plans/` — one document
per work package, each with measurable gates, named open problems, and a
closing "what this document does not promise" section. Anything implying
unbuilt code carries a dated marker ("decided 2026-08, lands with the v2
bump / P1 / P2"). Planned invariants **U8–U14** are specified in the
documents that motivate them and summarized across `ARCHITECTURE.md`'s
update notes and §11; they enter `CLAUDE.md` as binding invariants only
when their enforcing code and tests land (U11 entered 2026-08-20, U9
2026-09-14). factbond's mirror corpus is
`factbond/docs/plans/`.

## Vocabulary

Four words carry the design and are used precisely since 2026-09-07:

- **loop** — any cleared circulation: the essay's word and the name in code (`Loop`, `LoopProposal`, `loop/`, `loop_id`).
- **cycle** (simple loop) — the strict circle; all the P0 solver finds, and the only case where "the product of rates around it" means anything.
- **circulation** — the technical name for the cleared object: a flow conserved at every maker on that maker's own scale, with composed legs where one want takes several gives (`docs/plans/P2-loop-selection.md` §10–11).
- **hyper-leg** — a composed leg: several givers as tails, one wanting maker as head, one flow variable, so it fills every tail or none. The maker graph with hyper-legs is a hypergraph; its flow is an LP for divisible legs and an ILP where a hyper-leg is all-or-nothing.

And two pairs more: **clearing** is the atomic commit that fixes obligations; **settlement** is the makers delivering. An **arbitrator** decides a contested claim in the default form (the offer's `arbitrator` field); a **resolver** is the address the escrow lets hold and resolve a reservation — an arbitrator's key, or factbond's contract, whose rungs are its *adjudicator* and *arbiter*.

## The plan corpus

| Document | One line |
|---|---|
| [`P1-federated-book.md`](docs/plans/P1-federated-book.md) | Per-maker books under own feeds/signers; announcement, aggregation, merge discipline, lifecycle, postage economics, spam floors. |
| [`P1-spacetime-terms.md`](docs/plans/P1-spacetime-terms.md) | Place and time leave the offer's fields for its conjunction (decided and built through the v3 record 2026-09-12): where/when a thing changes hands are terms like its categories, cells and region nodes the exact geo truth, the disc retired; since 2026-09-13 handover coordinates match when one side contains the other, categories one way (the overlap rule of 2026-09-12 superseded). |
| [`P2-batch-auction.md`](docs/plans/P2-batch-auction.md) | The beat: sealed proposals, numeraire-free scoring, the fairness floor, the baseline as reserve bid, collusion resistance; no protocol fees (the fee-funded solver rewards were struck 2026-08-21). §2–§6 built 2026-09-18 (`SealedBeat.sol`, `auction.py`). |
| [`P2-clearing-pricing.md`](docs/plans/P2-clearing-pricing.md) | Turning a winning loop's surplus into per-leg prices: equal log-surplus split under uniform directional clearing; clearing prices as node potentials (§10). |
| [`P2-loop-selection.md`](docs/plans/P2-loop-selection.md) | Clearing as optimization: flow LP vs packing ILP, chains, failure-aware objective, pre-commit compression; composition on the want side (§10); the cleared object is a circulation, clearing prices its node potentials (§11). |
| [`proof-fabric.md`](docs/plans/proof-fabric.md) | Cross-phase proofs and certificates: trie proofs vs POT, the pin table, certificate envelopes, absence proofs. |
| [`P3-guarantee-coupling.md`](docs/plans/P3-guarantee-coupling.md) | loopmarket's half of the factbond coupling: witness edges, reliance-capped insurance, oracle consumption, risk-priced routing. |
| [`P3-release-and-reclearing.md`](docs/plans/P3-release-and-reclearing.md) | Release prices and re-clearing (direction set 2026-09-18): a maker's required floor is its true neutral point, a self-assessed buyout price anyone may pay to cancel its side of a cleared leg; re-clearing as cancel-and-replace in one transaction; the Pareto re-match first and free; payments in the bond's asset by the entrant, never from surplus. Built from it: the v5 record's admissibility by declaration (§5d) and the escrow (§5a), 2026-09-19; adjudication is factbond's (§5e). |
| [`credentials-cover-and-options.md`](docs/plans/credentials-cover-and-options.md) | loopmarket's index to the cross-repository plan decided 2026-09-25 (D1–D10 and their amendments; the full text lives in factbond): which decisions are carried out here, and where. |
| [`counterparty-gate.md`](docs/plans/counterparty-gate.md) | Counterparty requirements as categories, one statement shape, registers separately rooted and pinned, revocation proven by absence under a root no older than the requirer allows; the build R1–R7, R3b's chain half and R5's checked root sequence (built 2026-09-29). |
| [`options-and-cover.md`](docs/plans/options-and-cover.md) | An option is a hold on a plain offer, written by clearing and lapsing with time; options and cover share one model with two exercise routes; holds on chain (C4, built and deployed 2026-09-29). |
| [`items-and-ownership.md`](docs/plans/items-and-ownership.md) | `item(h)` for unique things, one open claim per maker and item (D5), ownership kept out of clearing — "not his to sell" is non-performance; item claims on chain (I3, 2026-09-29). |
| [`commercial-practice-review.md`](docs/plans/commercial-practice-review.md) | Reference: do the mechanisms encourage what merchants, private courts and mutuals learned over centuries? Its amendments are woven into the credentials plan. |
| [`P4-privacy.md`](docs/plans/P4-privacy.md) | Staged privacy: Tier 1 with zero new cryptography, the P2 format-freeze list, explicit dead/deferred rulings. |
| [`ontodag-coupling.md`](docs/plans/ontodag-coupling.md) | The catalogue contract: dimension terms, unit families, match degrees, the upstream-vs-local tripwire table. |
| [`cli.md`](docs/plans/cli.md) | The command line (designed 2026-09-11, **built 2026-09-12** as `loop`): ontodag's grammar plus quantity-first/price-last, every term the catalogue's, last-price memory, "declare in the direction you know" instead of a tolerance parameter, the approval block, batch scripts; what is still open (the upstream asks, §11). |
| [`catalogue-bootstrap.md`](docs/plans/catalogue-bootstrap.md) | Seeding and governing the shared catalogue: seed taxonomies, the import pipeline, norms as protocol rules. |
| [`adoption-and-thickness.md`](docs/plans/adoption-and-thickness.md) | Where the first loops come from: launch verticals, the broker surface, bridge liquidity, thickness engineering. |
| [`THREATS.md`](docs/plans/THREATS.md) | The threat register, T1–T20 (the fixed T1–T9 by expected damage to a young system, then dated additions — T19, biometric linkage at the door; T20, a resolver's stake thinner than it reads); mirrored in factbond. |
| [swarm-da](https://github.com/petfold/swarm-da) (separate repo) | Memo, 2026-09-09: what building this book on Swarm taught about Swarm as a data-availability layer — the archival-DA opportunity, Bee's push-sync receipts as the half-built publication primitive, and what loopmarket sheds the day they are exposed and anchored. |

**Phase ↔ document map.** P1 (federation): `P1-federated-book.md`,
supported by `ontodag-coupling.md` and `catalogue-bootstrap.md`, with
`cli.md` as its tooling. P2
(verifiable clearing): the three P2 docs plus `proof-fabric.md`,
*constrained* by `P4-privacy.md`'s format-freeze list and gated by
`THREATS.md` tripwires. P3 (guarantee fabric): `P3-guarantee-coupling.md`
plus factbond's entire corpus — gated by factbond's Phase-0 simulation
going green *and* the P2 format freeze — and, since 2026-09-25, the
credentials track: `credentials-cover-and-options.md` indexing
`counterparty-gate.md`, `options-and-cover.md` and `items-and-ownership.md`,
reviewed against practice in `commercial-practice-review.md`. P4 (privacy): `P4-privacy.md`,
whose Tier 1 may ship alongside P2. Cross-phase: `proof-fabric.md`,
`THREATS.md`, `adoption-and-thickness.md`, `catalogue-bootstrap.md`,
`ontodag-coupling.md`.

**Reading order.** First pass: `ARCHITECTURE.md` → `THREATS.md` →
`P1-federated-book.md`. Clearing track: `P2-loop-selection.md` →
`P2-clearing-pricing.md` → `P2-batch-auction.md` → `proof-fabric.md`.
Guarantee track: factbond `DESIGN.md` → `mechanism-design.md` →
`insurance-products.md` → `phase0-simulation.md` →
`P3-guarantee-coupling.md`. Market track: `adoption-and-thickness.md` →
`catalogue-bootstrap.md` → `ontodag-coupling.md`.

Order of documents is not order of construction — gates decide that; and a
document's existence proves nothing about feasibility. The Phase-0
simulation and the named empirical gates can kill designs recorded here;
the corpus is built so that they can.

## Documentation

- **[docs/USER-GUIDE.md](docs/USER-GUIDE.md)** — the tutorial: from your
  first offer to a federated book on a live Swarm network, every snippet
  runnable.
- **[docs/REFERENCE.md](docs/REFERENCE.md)** — the reference manual:
  every public class and function, the keyspace, record formats,
  invariants, environment.
- **[ARCHITECTURE.md](ARCHITECTURE.md)** — the design and its rationale:
  the uniform offer form, time/place as fits-within dimensions, the book's
  keyspace and multi-writer story, the loop arithmetic (and why prices are
  never negative), the trust model, the proof fabric, economic security,
  and what the architecture does not promise.
- **[ROADMAP.md](ROADMAP.md)** — the phase index with status:
  P0 (built) → P1 (federated book, live since 2026-08-21) → P2 (verifiable
  clearing, batch auctions) → P3 (guarantee fabric via factbond) →
  P4 (privacy), each linking to its plan document.
- **[CLAUDE.md](CLAUDE.md)** — working rules for development: dependency
  boundaries, core invariants U1–U7, U9 and U11, known simplifications.
- **[docs/loop-economy.md](docs/loop-economy.md)** — the vision essay: the
  loop economy, its gallery of loops, the solver ecology, judges without
  swords, and the path in.
