Local Canton from a clean clone
This repository does not require Canton DevKit. It supports two local network experiences with different boundaries:
| Path | Additional prerequisite | What it proves | What it does not prove |
|---|---|---|---|
| DPM sandbox proof (default) | none beyond the pinned DPM SDK | Real Canton process, JSON Ledger API, current DEX DAR with its Token Standard closure, distinct LP/swapper parties, and add → swap → remove DvP settlement | Splice wallet/scan UIs, multi-participant topology, browser/backend HTTP, external wallet |
| DevKit LocalNet (optional) | a separately distributed canton-devkit executable and Docker |
Full persistent Splice LocalNet services plus the same DEX live driver | Production topology/security and an automated browser-wallet test |
The DEX application and its DARs have no runtime dependency on DevKit. The
optional script is a lifecycle and credential adapter: it starts or reuses the
named developer network, but the separately distributed canton-devkit
executable must already be installed.
Prerequisites
Section titled “Prerequisites”Both paths need:
- Node.js 24 or newer
- Java 17
- DPM and the SDK version pinned in
trading/daml.yaml curl, Bash, and npm
Verify them from the repository root:
node --versionjava -versiondpm --versioncurl --versionThe default proof does not need Docker. The optional DevKit path does.
Path A: portable DPM sandbox proof
Section titled “Path A: portable DPM sandbox proof”Run:
bash scripts/run-dpm-sandbox-proof.shThe script performs these visible phases:
- Installs SDK 3.5.2 idempotently and builds
canton-dex-trading. - Reserves all six Canton ports, releases them together, and starts the SDK’s
dpm sandboximmediately on those concrete loopback ports. - Waits for
/v2/state/ledger-end; readiness is proven, not assumed. - Creates one unrestricted user only inside this unauthenticated throwaway sandbox. The bootstrap party is operator/admin/LP registrar; the script then allocates a distinct LP/trader party and a distinct swapper party.
- Uploads exactly the newly built trading DAR selected by
trading/daml.yaml; the DAR embeds its Token Standard dependency closure. - Runs the direct JSON-API driver through add liquidity, a quote-bound swap, and redemption of half the LP position.
- Checks exact balances and reserves, active-slice sums after every phase, LP
holding/supply/policy agreement,
x*ynondecrease, reserve-per-LP, and aggregate base/quote value conservation. - Stops Canton and removes its temporary state after a pass.
The final checkpoint is:
==> PASS: portable live-Canton proof completed The throwaway sandbox is now stopping; no persistent ledger state remains.If a phase fails, the script preserves its temporary directory and prints the
path containing canton.log and canton.stdout.log. It never prints a JWT—the
DPM sandbox has authentication disabled and the placeholder bearer value is not
a credential.
Party and credential model
Section titled “Party and credential model”The proof needs real counterparties: the LP/trader, swapper, and operator are
three distinct Canton parties. This prevents a deposit or swap from degenerating
into a transfer from a party to itself. The operator party also acts as asset
admin and LP registrar for this self-contained fixture, however, and the single
sandbox user has CanExecuteAsAnyParty, CanReadAsAnyParty, and
ParticipantAdmin rights. That is deliberately convenient throwaway setup,
not a production authorization model.
Focused Daml tests cover finer-grained controller failures with separate parties. A deployment sign-off must additionally prove its actual users, JWTs, and least-privilege rights with the Validator Test Plan.
What this proof intentionally bypasses
Section titled “What this proof intentionally bypasses”The driver submits JSON Ledger API commands directly. It does not start:
- the operator HTTP server;
- the React dApp;
- a wallet extension or PartyLayer;
- a multi-participant Splice network.
Passing it is live-ledger integration evidence, not browser full-stack E2E evidence. The testing boundary matrix is the authoritative scope definition.
Path B: optional persistent DevKit LocalNet
Section titled “Path B: optional persistent DevKit LocalNet”Use this only when your development environment already distributes
canton-devkit:
command -v canton-devkitcanton-devkit versionIf the first command prints nothing, skip this path. The repository does not silently download or install an unpinned network manager. Use Path A, an organization-approved DevKit installation, or the official Canton Network Quickstart selected by your deployment team.
Docker must be running. Then execute:
bash scripts/run-localnet-roundtrip.sh canton-dexThe integration wrapper:
- runs
canton-devkit localnet doctor; - starts or reuses the named
0.6.12instance; - imports the app-provider endpoint and JWT inside the process without printing the token;
- discovers the ledger user’s primary party;
- builds/uploads the DEX package closure; and
- allocates an LP/trader and swapper through the standard JSON Ledger API when explicit party overrides are absent; and
- executes the same add → quote-bound swap → half-LP-remove driver.
Unlike Path A, it deliberately leaves the instance running so you can inspect contracts and transactions:
canton-devkit localnet status --name canton-dexcanton-devkit localnet contracts --helpcanton-devkit localnet tx --helpStop containers while preserving the instance volumes:
canton-devkit localnet down --name canton-dexThe following is destructive and deletes that named instance’s ledger state:
canton-devkit localnet remove --name canton-dexOverride the generated live parties
Section titled “Override the generated live parties”By default the wrapper uses the app-provider primary party for operator/admin/ LP-registrar and allocates missing LP/trader and swapper parties through the JSON Ledger API. To exercise pre-provisioned parties instead, ensure the DevKit ledger user can act as them, then run:
DEX_LOCALNET_OPERATOR="<operator-party>" \DEX_LOCALNET_ADMIN="<admin-party>" \DEX_LOCALNET_TRADER="<trader-party>" \DEX_LOCALNET_SWAPPER="<swapper-party>" \bash scripts/run-localnet-roundtrip.sh canton-dexThe LP registrar currently follows DEX_LOCALNET_ADMIN for the self-registry
test fixture. The trader and swapper must each differ from the operator. A
production deployment normally uses distinct roles and the participant-specific
setup in Run against a Canton testnet.
Path C: bring your own participant
Section titled “Path C: bring your own participant”Neither local launcher is required when you already have a participant. Export
the exact contract-party/package environment listed in
Testing, run the backend package
script from services/operator-backend, and treat every live probe as
state-mutating. For a long-lived deployment, follow
Run against a Canton testnet.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Meaning and action |
|---|---|
dpm: command not found |
Install DPM first; the portable proof cannot start Canton without the pinned SDK. |
| Java class-version/startup error | Activate Java 17 and rerun java -version. |
| Canton is not ready after 120 seconds | Read the preserved log directory printed by the proof; check memory and port-binding errors. |
/v2/packages rejects a DAR |
The target participant does not accept the committed dependency hash or the DEX DAR was not rebuilt. On a governed network, vet the exact package closure. |
USER_NOT_FOUND |
The driver user was not created on a manual participant. The portable script creates it automatically only in its throwaway sandbox. |
PERMISSION_DENIED for actAs |
The participant JWT user lacks rights for one of CANTON_OPERATOR, CANTON_ADMIN, CANTON_LP_REGISTRAR, or CANTON_TRADER. |
canton-devkit: command not found |
DevKit is optional; use the DPM sandbox proof or install it through an approved distribution. |
Where to read next: AMM-first walkthrough · Testing · Deployment