From d4b2835589b4700e21626a93d5648b614338d735 Mon Sep 17 00:00:00 2001 From: srikanth-bitdynamics <259878899+srikanth-bitdynamics@users.noreply.github.com> Date: Sun, 2 Aug 2026 21:40:52 +0530 Subject: [PATCH 1/2] docs: add non-goals note and ecosystem-feedback summary The non-goals note collects what the reference intentionally excludes and why. The ecosystem-feedback page records the external integration, the findings from it, and the resulting changes. --- docs/README.md | 4 +- docs/concepts/architecture.md | 5 +- docs/concepts/non-goals.md | 95 +++++++++++++++++++++++++++ docs/reference/ecosystem-feedback.md | 96 ++++++++++++++++++++++++++++ 4 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 docs/concepts/non-goals.md create mode 100644 docs/reference/ecosystem-feedback.md diff --git a/docs/README.md b/docs/README.md index 79ee43d7..9f393ff5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -29,7 +29,7 @@ For the ideas behind the design, read the **[Overview](concepts/overview.md)**. | **Operate a venue** | [Deployment](guides/deployment.md) → [Operator Guide](guides/operator-guide.md) → [Operator Runbook](guides/operator-runbook.md) | | **Integrate a registry** | [Registry Integration](guides/registry-integration.md) → [Choice Context](guides/choice-context.md) → [Allocation Surface](reference/allocation-surface.md) | | **Trade in the dApp** | [Using the dApp](guides/using-the-dapp.md) | -| **Evaluate / review it** | [Overview](concepts/overview.md) → [Architecture](concepts/architecture.md) → [Glossary](concepts/glossary.md) | +| **Evaluate / review it** | [Overview](concepts/overview.md) → [Architecture](concepts/architecture.md) → [Non-goals](concepts/non-goals.md) → [Ecosystem feedback](reference/ecosystem-feedback.md) | --- @@ -54,6 +54,7 @@ lookup (reference). | [LP Tokens](concepts/lp-tokens.md) | Builder, integrator | Why LP tokens are a single, unversioned V2 instrument per pool. | | [Pricing](concepts/pricing.md) | Operator, integrator | Where prices come from — pool-derived, order book, RFQ — and the (absent) oracle attachment points. | | [Glossary](concepts/glossary.md) | Everyone | The key terms: allocation, commitment, iterated settlement, DvP, slice, registrar, and more. | +| [Non-goals](concepts/non-goals.md) | Everyone | What the reference intentionally does not include, and why. | ### Guides — do a task | Page | Audience | Recipe | @@ -76,6 +77,7 @@ lookup (reference). | [HTTP API](reference/http-api.md) | The operator-backend HTTP endpoints, wallet intents, and error codes. | | [Allocation Surface](reference/allocation-surface.md) | The V2 allocation surface this reference relies on (committed allocations, iterated settlement). | | [Testing](reference/testing.md) | The real-ledger, JSON Ledger API end-to-end test driver. | +| [Ecosystem feedback](reference/ecosystem-feedback.md) | How the reference was evaluated externally, what was found, and what changed. | --- diff --git a/docs/concepts/architecture.md b/docs/concepts/architecture.md index 3580f420..08666819 100644 --- a/docs/concepts/architecture.md +++ b/docs/concepts/architecture.md @@ -4,8 +4,9 @@ Canton DEX is a token-standard-native reference DEX for Canton. -It is intentionally not a generic settlement engine. The goal is to show -builders how to build a real exchange directly on top of: +It is intentionally not a generic settlement engine. What the reference leaves +out on purpose, and why, is collected in [Non-goals](non-goals.md). The goal is +to show builders how to build a real exchange directly on top of: - Token Standard V2 allocations and batch settlement - registry-backed holdings whose registries implement the V2 holding, diff --git a/docs/concepts/non-goals.md b/docs/concepts/non-goals.md new file mode 100644 index 00000000..7faee7ca --- /dev/null +++ b/docs/concepts/non-goals.md @@ -0,0 +1,95 @@ +# What this reference does not include, and why + +This is a reference implementation, not a product. Several things a production +DEX would carry are left out on purpose — either because they are an operator's +choice rather than a settlement-pattern concern, or because including them would +obscure the one thing the reference exists to show: that spot trading on Canton +can be built entirely on Token Standard V2 allocations, with the ledger enforcing +custody and conservation. + +Each exclusion below is a decision, not an omission. Where a boundary is visible +in the code, the module is named. + +## Not a generic settlement engine + +The Daml models a DEX: pools, orders, RFQ. It is not a configurable settlement +framework that a caller parameterises into arbitrary flows. The settlement +*pattern* — allocate, then settle a batch atomically through the registry's +`SettlementFactory` — is meant to be read and reused, but the templates encode +the DEX's own rules (constant-product pricing, price-time order priority, +best-execution RFQ ranking) rather than exposing a general engine. +See [architecture.md](architecture.md). + +## One registry admin per pair + +A trading pair carries a single `admin : Party` covering both its base and quote +instruments (`trading/CantonDex/Dex/Order.daml`, `Pool.daml`). Under Token +Standard V2 an instrument is identified by `(admin, id)`, so this reference cannot +list a pair whose two assets come from different registries — for example Canton +Coin quoted against a third-party stablecoin. The settlement layer itself does +*not* require this (a single Daml transaction can settle one batch per admin, and +this repository already does so on the LP path); the limitation is in the app-layer +templates. Lifting it is a scoped design change, written up separately, not a gap +in the pattern. + +## Not a production matching engine + +Order matching is a batch process the operator runs (`runMatching` in +`services/operator-backend/src/order/index.ts`), not a continuous in-ledger +matching loop. It clears crossing orders best-price-then-time, settles each match +atomically, and applies simple self-trade prevention (a party's own orders are +not paired). It does not implement pro-rata allocation, iceberg or hidden orders, +matching priority tiers, or a continuous auction. A production venue would layer +those on; the reference shows that the *settlement* of a match is atomic and +allocation-backed, which is the part specific to Canton. + +## A minimal instrument model + +The vendored standard holding model is kept intentionally small. The reference +issues exactly one lifecycle-bearing instrument — the LP token — as a +token-standard instrument with its own registrar and DvP mint/burn +(`trading/CantonDex/Lp/`). Token Standard V2 does not mandate +`InstrumentConfiguration` or a rich lifecycle, and the reference does not assume +one exists for every registry. A guide for issuing a lifecycle-richer instrument +is included ([../guides/add-lp-or-instrument.md](../guides/add-lp-or-instrument.md)), +but the reference itself stays at the minimum the DEX needs. + +## The reference registry is one option, not the mechanism + +`CantonDex.Registry.V2` is a self-contained reference registry so the DEX can be +run end to end without depending on an external one. It is not the settlement +mechanism. The dApp and operator reach any conforming TSv2 registry through its +factories, choice context and disclosure — the reference does not assume its own +registry is present, and does not require every registry to expose the same +conveniences (`architecture.md`, "Dependency Boundary"). On the public testnet +the pair's assets happen to be issued by this registry; the flows are written to +work against Amulet or any other conforming registry. + +## The hosted testnet is a demo surface, not a wallet + +The public deployment lets a visitor with no wallet trade, by minting a hosted +demo party and relaying its signatures through a fixed, allowlisted set of +choices under per-IP and daily caps. This is explicitly a testnet convenience, +not self-custody: the two connect options are marked **DEV**. A real user brings +their own wallet (PartyLayer or the dapp-sdk) and signs for themselves; the hosted +relay exists so the milestone flows can be exercised from a browser without one. +The hosted onboarding routes and their caps are documented in +[../guides/operator-runbook.md](../guides/operator-runbook.md). + +## Operational hardening is out of scope + +The reference includes an operator runbook covering deployment, recovery and +observability, but it is not a hardened production service. There is no HA, no +rate-limited public gateway beyond the testnet caps, no secrets-management +integration, and the operator's authority is a single party. These are an +operator's deployment decisions, deliberately left to whoever runs an instance +rather than baked into the reference. + +## Off-chain services are illustrative + +The operator backend and indexer are a working reference, not a prescription. The +indexer is a single-writer SQLite projection sized for a testnet; the backend is +one Node process. They show *what* an integrator needs to read and relay, not the +only way to build it. The on-ledger contracts are the specification; the +off-chain services are one implementation of the surface around them +(`architecture.md`, "Off-Chain Services"). diff --git a/docs/reference/ecosystem-feedback.md b/docs/reference/ecosystem-feedback.md new file mode 100644 index 00000000..845d2b9d --- /dev/null +++ b/docs/reference/ecosystem-feedback.md @@ -0,0 +1,96 @@ +# Ecosystem feedback and resulting design changes + +This page records how the reference implementation was evaluated by external +parties, what they found, and what changed as a result. It is maintained as the +single summary of that loop. + +## External integration (reuse proof point) + +The reference DEX is integrated as an adapter in +[**canton-trading-toolkit**](https://github.com/olevasyliev/canton-trading-toolkit), +an independent, open-source, venue-agnostic trading client for the Canton +Network. The toolkit is live-validated on mainnet against an unrelated spot AMM +(Cantex) and connects to a perpetuals testnet (Ekiden); this DEX is a third +adapter (`DexRefAdapter`). The significance is that the *same client code* that +trades on an unrelated mainnet venue drives quotes, swaps, orders, matching, RFQ +and liquidity on this one, entirely through the hosted testnet routes — the only +path open to a party with no wallet of its own. + +The integration is reproducible from outside with no operator credentials: + +``` +git clone https://github.com/olevasyliev/canton-trading-toolkit +cd canton-trading-toolkit && pip install -e . +PYTHONPATH=src python3 scripts/dexref_testnet_report.py # reads only +PYTHONPATH=src python3 scripts/dexref_testnet_report.py --execute # trades +``` + +The client allocates its own parties from the public faucet and exercises every +flow against `https://testnet-dex.bitdynamics.cc`. This is the concrete reuse +proof point: an external developer built a working integration against the hosted +testnet, from the public repository, and published it. + +## Evaluation and feedback + +The integrator ran six rounds against the hosted testnet between 2026-07-27 and +2026-07-29, plus an earlier round against the repository's local demo mode. Each +round is a scripted run of dozens of assertions measured through the public +routes. The reports are public: + +- Hosted testnet report: + [srikanth-bitdynamics/Canton-Dex-Reference-Implementation#126](https://github.com/srikanth-bitdynamics/Canton-Dex-Reference-Implementation/issues/126) +- Local demo mode report: + [canton-dev-fund#312 comment](https://github.com/canton-foundation/canton-dev-fund/issues/312#issuecomment-5044174855) + +Because the integrator has no privileged access, the findings are exactly what any +external builder would hit, which is what makes them useful. + +## Findings and resulting changes + +Every finding from the six rounds was addressed. They fall into a few themes. + +**Precision and wire correctness.** Amounts must be served at ledger precision as +exact decimal strings, not re-floated. Fixes: the fills feed no longer routes +deltas through `parseFloat().toFixed` (F13); `/v1/swaps` serves the exact strings +rather than re-floating them (F20); `/v1/instruments` reports each instrument's +`decimals`, so a client can learn scale from the API; pre-fix rows were backfilled +rather than left wrong (F21). + +**Read-surface consistency.** External clients depend on the read API being +uniform. Fixes: the status wire value stopped shipping a `PS_`-prefixed enum the +dApp silently stripped (F11); `/v1/orders/book` accepts `?pair=` like every other +read (F15, additively); the trades feed no longer inverts trader and dealer on +buys (F16); `/v1/trades` includes `counterparty` after the deployment was brought +current with `main` (F22); an unscoped, unauthenticated `GET /v1/rfq` that lived +only on a soon-to-be-retired branch was fixed on `main` (F23). + +**Funding and custody correctness.** Fixes: funding an order locks only what the +order needs and returns the change, so a party can place more than one order +(F12); the off-ratio liquidity add refunds the unmatched remainder and the hosted +receipt reports the settled amounts rather than echoing the request (F25). + +**Completing the hosted surface.** The hosted routes are the only path for a +walletless integrator, so gaps in them block external evaluation entirely. Fixes: +RFQ gained a hosted cancel, so a round trip has an exit other than expiry (F17); +order matching gained a hosted, unauthenticated trigger (`POST /v1/testnet/match`) +so matching and its atomic settlement can be verified from outside (F24); +`/v1/swaps` gained `?kind=` so liquidity events, not just swaps, are readable +(F26). The whole `/v1/testnet/*` surface and the faucet's per-IP party quota were +documented with their consequences (F14, F18). + +**Behaviour explained rather than changed.** Some reports were answered by design: +`Holding_Split` is refused by the hosted relay because the relay admits only a +fixed choice allowlist, and splitting is a wallet concern the relay does not +expose (F19). + +One item remained open at the time of the report and has since been closed: a +resting order the book published but the matcher would not pair (F27). The cause +was a self-cross — a party's own bid and ask — which can never settle. The matcher +now applies self-trade prevention and no longer proposes it. + +## How this loop is expected to continue + +The reference tracks the same standard the ecosystem builds against, and its +hosted testnet is open for exactly this kind of evaluation. New reports open as +issues on the implementation repository; confirmed findings are fixed with a +regression test and this summary is updated. From fabc6b0c918439958287e0bc6389a3e476e9596d Mon Sep 17 00:00:00 2001 From: srikanth-bitdynamics <259878899+srikanth-bitdynamics@users.noreply.github.com> Date: Sun, 2 Aug 2026 21:49:23 +0530 Subject: [PATCH 2/2] docs: note the interim hosted-onboarding deployment status The public testnet onboards testers as hosted parties on the operator's validator, with assets issued locally by its own Token Standard V2 registry, until the general-purpose wallet tooling supports V2. --- docs/concepts/non-goals.md | 12 ++++++++++++ docs/guides/using-the-dapp.md | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/docs/concepts/non-goals.md b/docs/concepts/non-goals.md index 7faee7ca..5a9ca542 100644 --- a/docs/concepts/non-goals.md +++ b/docs/concepts/non-goals.md @@ -76,6 +76,18 @@ relay exists so the milestone flows can be exercised from a browser without one. The hosted onboarding routes and their caps are documented in [../guides/operator-runbook.md](../guides/operator-runbook.md). +**Current deployment status.** On the public testnet at +`testnet-dex.bitdynamics.cc`, every tester is onboarded as a hosted party on the +operator's (BitDynamics) validator, and every traded asset — `dBTC`, `dUSD`, and +the pool's LP token — is issued locally by the deployment's own Token Standard V2 +registry. This is a bridge: external participants cannot yet bring their own +Token Standard V2 party and assets because the general-purpose validator and +wallet tooling (DA Utilities) does not yet support Token Standard V2. When that +support ships, users connect their own participant's party and trade their own V2 +assets through PartyLayer or the dapp-sdk, and the hosted onboarding is retired. +The code path for that is already the intended one — the hosted relay is the only +piece specific to this interim. + ## Operational hardening is out of scope The reference includes an operator runbook covering deployment, recovery and diff --git a/docs/guides/using-the-dapp.md b/docs/guides/using-the-dapp.md index 82404958..c9fb77e2 100644 --- a/docs/guides/using-the-dapp.md +++ b/docs/guides/using-the-dapp.md @@ -28,6 +28,13 @@ local dev builds, never in production or testnet. Once connected, your party id appears in the top bar. The wallet provider persists across reloads (session is stored in `localStorage`). +On the public testnet at `testnet-dex.bitdynamics.cc`, testers are onboarded as +hosted parties on the operator's (BitDynamics) validator, and the traded assets +are issued locally by the deployment's own Token Standard V2 registry. This is an +interim arrangement until the general-purpose validator and wallet tooling (DA +Utilities) supports Token Standard V2, at which point users bring their own party +and V2 assets. See [Non-goals](../concepts/non-goals.md#the-hosted-testnet-is-a-demo-surface-not-a-wallet). + --- ## Swap (Trade page)