Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a87844c
feat(canton-dappbooster): read another party's holdings with readHold…
gabitoesmiapodo Nov 11, 2026
b1503b1
feat(token-vault): add the token vault example package
gabitoesmiapodo Nov 11, 2026
0fbe397
feat(token-vault): port the vault dApp onto the token-vesting shell
gabitoesmiapodo Nov 11, 2026
9c9ee8b
feat(token-vault): add the vault bootstrap and operator scripts
gabitoesmiapodo Nov 11, 2026
6367cc0
feat(canton-create): offer the token vault example
gabitoesmiapodo Nov 11, 2026
af31573
fix(token-vault): say what a DAR re-upload answers on a LocalNet
gabitoesmiapodo Nov 11, 2026
df012d3
docs(token-vault): document the token vault example
gabitoesmiapodo Nov 11, 2026
50b4ea4
docs(canton-create): record the installer demo again
gabitoesmiapodo Nov 11, 2026
69027ce
fix(canton-dappbooster): return only the holdings a party owns
gabitoesmiapodo Nov 11, 2026
b1028b3
fix(token-vault): order the queue by accept time and drop amountless …
gabitoesmiapodo Nov 11, 2026
5d4e606
fix(token-vault): pick the vault party in the bootstrap as the dApp does
gabitoesmiapodo Nov 11, 2026
2f353f8
fix(token-vault): skip expired requests and read each tick at one offset
gabitoesmiapodo Nov 11, 2026
13c99c2
refactor(token-vault): trim the dApp to what it uses
gabitoesmiapodo Nov 11, 2026
fe520c9
refactor(token-vault): share the scripts' ledger helpers
gabitoesmiapodo Nov 11, 2026
f08eddb
Merge remote-tracking branch 'origin/feat/254-amulet-vesting-walletle…
fernandomg Nov 13, 2026
61724ce
fix(token-vault): read the ledger the way Canton 3.6 still accepts
fernandomg Nov 13, 2026
761c5bc
chore(deps): move the token vault example to jsdom 31
fernandomg Nov 13, 2026
b72befb
docs: fix the token vault's doc inconsistencies
fernandomg Nov 13, 2026
591ed26
Merge remote-tracking branch 'origin/main' into feat/253-token-vault
fernandomg Nov 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Each subproject can layer its own `CLAUDE.md` for stack-specific deltas:
- [`example-dapps/amulet-vesting/CLAUDE.md`](example-dapps/amulet-vesting/CLAUDE.md): the vesting example's deltas. Its seams are in [`example-dapps/amulet-vesting/architecture.md`](example-dapps/amulet-vesting/architecture.md), and its Daml in `daml/README.md`
- [`example-dapps/amulet-vesting-walletless/CLAUDE.md`](example-dapps/amulet-vesting-walletless/CLAUDE.md): the wallet-less vesting example's deltas: its server, the session and the participant user's rights. Its seams are in [`example-dapps/amulet-vesting-walletless/architecture.md`](example-dapps/amulet-vesting-walletless/architecture.md)
- [`example-dapps/token-vesting/CLAUDE.md`](example-dapps/token-vesting/CLAUDE.md): the token vesting example's deltas. Its seams are in [`example-dapps/token-vesting/architecture.md`](example-dapps/token-vesting/architecture.md), its committed DARs included
- [`example-dapps/token-vault/CLAUDE.md`](example-dapps/token-vault/CLAUDE.md): the token vault example's deltas: the participant-hosted vault party, the two template-id spellings and the one dApp module that reads the `InstrumentConfig` disclosure. How it works inside is in [`example-dapps/token-vault/architecture.md`](example-dapps/token-vault/architecture.md), its committed DARs included

The dApp connects through any CIP-0103 wallet; no wallet lives in this monorepo.

Expand Down Expand Up @@ -47,6 +48,7 @@ Current distribution:
| `example-dapps/amulet-vesting/` | yes | shim | yes | yes | Canton Coin vesting example, published on its own. `CLAUDE.md` carries its deltas, and architecture.md its internal seams. Its single Daml package (`amulet-vesting`) sits in `daml/` with a `README.md` of its own. Its `CLAUDE.md` names the repository and commit `daml/` came from. |
| `example-dapps/amulet-vesting-walletless/` | yes | shim | yes | yes | The Canton Coin vesting example with accounts instead of a wallet, published on its own. `CLAUDE.md` carries the server's rules, and architecture.md the session, the API and the ledger seams. Its `daml/` is an identical copy of `amulet-vesting`'s. |
| `example-dapps/token-vesting/` | yes | shim | yes | yes | Token vesting example, published on its own. It started as a copy of the Amulet one; its `CLAUDE.md` carries the `api/` and `vendor/` rules. Its Daml packages are binaries in `vendor/`, and its `architecture.md` records their releases and checksums. |
| `example-dapps/token-vault/` | yes | shim | yes | yes | Token vault example, published on its own: deposit a canton-token-forge token for vault shares, redeem shares. Its `CLAUDE.md` carries the vault party, the ledger read and the `vendor/` rules. Its Daml packages are binaries in `vendor/`, and its `architecture.md` records their checksums and package ids. Its `scripts/vault-operator.mjs` acts as the vault party, started through `stack:up`. |
| `canton-dappbooster/` | yes | shim | yes | yes | L2 headless components; `CLAUDE.md` carries the folder-per-component layout an agent would otherwise get wrong, architecture.md the authoring seam (anatomy contract, L2/L3 split, Zag boundary). |
| `canton-theme/` | yes | shim | yes | no | Plain-CSS theme (L3); README covers the two CSS exports, `CLAUDE.md` the `--cnc-*` naming convention an agent adding a token would otherwise invent. |

Expand Down Expand Up @@ -130,6 +132,7 @@ stays only where it is the point: a pair the sentence contrasts, or a figure fix
| [`example-dapps/amulet-vesting/`](example-dapps/amulet-vesting/) | Canton Coin vesting dApp, an example `create-canton-dappbooster` scaffolds, published as `@bootnodedev/canton-example-amulet-vesting`. Every read and write goes through the connected CIP-0103 wallet via `canton-connect`; the operator's factory, the `AmuletRules` and the open mining round all arrive by explicit disclosure. Its `amulet-vesting` Daml model in `daml/` covers the factory, the proposal, the contract and the residual claim, and holds Canton Coin in escrow as a Splice `LockedAmulet`. It is vendored from [cc-vesting-contracts](https://github.com/BootNodeDev/cc-vesting-contracts), where its scenarios stay. Imported from `cn-dappbooster@feat/vesting-lite`. | Vite + React + Ark UI + lucide-react + Tailwind v4 + `zustand` + react-router + Daml | 3012 |
| [`example-dapps/amulet-vesting-walletless/`](example-dapps/amulet-vesting-walletless/) | The Canton Coin vesting dApp with username and password accounts instead of a wallet, published as `@bootnodedev/canton-example-amulet-vesting-walletless`. A Hono server in `server/` allocates a participant-hosted party per account, keeps the accounts, the sessions and each grant's escrow disclosure in Postgres, and acts on the ledger as the signed-in account's party. Its `daml/` is a copy of amulet-vesting's. `scripts/server.sh` starts Postgres and the server through `stack:up`. Imported from `canton-dappbooster-walletless`. | Vite + React + Ark UI + lucide-react + Tailwind v4 + `zustand` + react-router + Hono + Postgres + Daml | 3012, server 3040, Postgres 5433 |
| [`example-dapps/token-vesting/`](example-dapps/token-vesting/) | The same vesting dApp over a `DBT` instrument from [canton-token-forge](https://github.com/BootNodeDev/canton-token-forge), published as `@bootnodedev/canton-example-token-vesting`. A canton-token-forge registry serves the instrument and the one `InstrumentConfig` each write discloses, so no Splice reference data reaches a write. Its `vesting` and `canton-token-forge` DARs ship as binaries in `vendor/`, so it needs no `dpm`. Its bootstrap uploads them and writes the registry's settings to the gitignored `.env.registry`. `scripts/registry.sh` runs the registry, from the registry's git dependency. | Vite + React + Ark UI + lucide-react + Tailwind v4 + `zustand` + react-router | 3012, registry 3013 |
| [`example-dapps/token-vault/`](example-dapps/token-vault/) | A token vault dApp over a `USDX` instrument from [canton-token-forge](https://github.com/BootNodeDev/canton-token-forge), published as `@bootnodedev/canton-example-token-vault`. A depositor proposes and the vault accepts. The depositor funds the request through the wallet, and the vault settles. A deposit mints `VSH` shares; a withdraw burns them and pays `USDX` back. The vault party is participant-hosted. `scripts/vault-operator.mjs` acts as it over the JSON Ledger API, and `scripts/operator.sh` starts it through `stack:up`. Its `canton-token-vault` and `canton-token-forge` DARs ship as binaries in `vendor/`, so it needs no `dpm`, and its bootstrap uploads them. The dApp reads the vault, both instruments and their disclosures off the ledger, so it runs no registry. | Vite + React + Ark UI + lucide-react + Tailwind v4 + `zustand` + react-router | 3012 |
| [`canton-create/`](canton-create/) | The `create-canton-dappbooster` installer, published on its own. [`canton-create/architecture.md`](canton-create/architecture.md) covers how it builds a project. | TypeScript + Ink + React 19 + `tsdown` + `vitest` | n/a (command-line tool) |
| [`canton-connect/`](canton-connect/) | wagmi-style React hooks wrapping the `dapp-sdk` facade; the SDK owns discovery, the picker, the session and the transports | TypeScript + React 19 + `xstate` 5 + Biome | n/a (library) |
| [`canton-dappbooster/`](canton-dappbooster/) | L2 headless UI components for Canton dApps, built with `tsdown` and carrying no styling. It also holds the light/dark/system theme runtime that drives `data-theme`, and the pure utilities the components build on, the exact-decimal amount ones included. Styling lives in `canton-theme`. `src/index.ts` is the public API. `src/connect.ts` is the `/connect` sub-path, holding the components and the hook that read the wallet session so the main barrel stays free of the Canton SDK. | TypeScript + React 19 + `tsdown` + `vitest` + Biome | n/a (library) |
Expand Down Expand Up @@ -446,7 +449,7 @@ its `CLAUDE.md` owns that contract. Nothing below differs.
with `[ "$1" = "--" ] && shift`, which is what lets it take `-- <dar>`, and `dev-stack.sh` drops
a `--` wherever it sits. `create-canton-dappbooster` drops it too, because `pnpm create` forwards
it the same way.
- Local ports: the dApp dev server on 3012, Wallet Gateway on 3030, the token example's registry on 3013, set in its `scripts/bootstrap-vesting.mjs`, and the wallet-less example's server on 3040 and its Postgres on 5433, set in its `.env.example` and `server/compose.yaml`. Do not change the dApp's or the gateway's without updating `dev-stack.sh`, `wallet-gateway.config.json` (both in `canton-create/scaffold/localnet/`) and the `.env.example` defaults together.
- Local ports: the dApp dev server on 3012, Wallet Gateway on 3030, token-vesting's registry on 3013, set in its `scripts/bootstrap-vesting.mjs`, and the wallet-less example's server on 3040 and its Postgres on 5433, set in its `.env.example` and `server/compose.yaml`. Do not change the dApp's or the gateway's without updating `dev-stack.sh`, `wallet-gateway.config.json` (both in `canton-create/scaffold/localnet/`) and the `.env.example` defaults together.
- **A new workspace package gets a line in both pre-commit configs, in the same change.**
`.lintstagedrc.format.mjs` lists every folder Biome formats, and `.lintstagedrc.mjs` maps each
package's files to its tests. Neither finds a package by itself, and CI still passing hides the
Expand All @@ -465,7 +468,7 @@ its `CLAUDE.md` owns that contract. Nothing below differs.
`dependencies` on the same range. pnpm and
npm install peers on their own, yarn does not, and a consumer can turn that off. It can go back to
optional once upstream moves that import behind a dynamic one.
- `pnpm-workspace.yaml` lists the packages allowed to run build scripts under `allowBuilds`: `esbuild`, `protobufjs`, the three Wallet Gateway compiles natively (`better-sqlite3`, `cbor-extract` and `secp256k1`), and the token example's `@bootnodedev/canton-token-forge`. pnpm blocks anything else until someone adds it. That last one is a git dependency whose `prepare` builds the registry, and pnpm keys it by the commit its tag resolves to. Moving its tag means replacing that commit in the root `pnpm-workspace.yaml` and in the example's `_pnpm-workspace.yaml` together.
- `pnpm-workspace.yaml` lists the packages allowed to run build scripts under `allowBuilds`: `esbuild`, `protobufjs`, the three Wallet Gateway compiles natively (`better-sqlite3`, `cbor-extract` and `secp256k1`), and token-vesting's `@bootnodedev/canton-token-forge`. pnpm blocks anything else until someone adds it. That last one is a git dependency whose `prepare` builds the registry, and pnpm keys it by the commit its tag resolves to. Moving its tag means replacing that commit in the root `pnpm-workspace.yaml` and in the example's `_pnpm-workspace.yaml` together.
- Do not commit `.env.local`, `node_modules`, `dist/`, `dist-extension/`, or `.claude/settings.local.json` (covered by root `.gitignore`).

## `scripts/`
Expand Down
13 changes: 12 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ The dApp runs on http://localhost:3012, its token registry on http://localhost:3
Gateway on http://localhost:3030. The examples share the LocalNet, so stop one before you start
another.

### Token Vault dApp

```bash
pnpm dev:token-vault # interactive menu
pnpm dev:token-vault up # LocalNet, its DARs, vault operator, Wallet Gateway and dApp
pnpm dev:token-vault down # stop everything and keep the ledger
```

The dApp runs on http://localhost:3012 and Wallet Gateway on http://localhost:3030. The vault
operator opens no port; its log is `.dev-stack/vault-operator.log`.

### Wallet-less Amulet Vesting dApp

```bash
Expand Down Expand Up @@ -97,7 +108,7 @@ pnpm -C canton-create try:clean # stop the stack, reset the LocalNet and remov
## Where to read next

- [`architecture.md`](architecture.md) maps the stack: data flow, services and ports, auth, orchestration and packaging;
- each package's `README.md` says what it is and how to use it, and its `architecture.md` how it works: [`canton-connect`](canton-connect/architecture.md), [`canton-dappbooster`](canton-dappbooster/architecture.md), [`canton-create`](canton-create/architecture.md), [`amulet-vesting`](example-dapps/amulet-vesting/architecture.md), [`amulet-vesting-walletless`](example-dapps/amulet-vesting-walletless/architecture.md) and [`token-vesting`](example-dapps/token-vesting/architecture.md). `canton-theme` has none: the split between components and theme is in canton-dappbooster's;
- each package's `README.md` says what it is and how to use it, and its `architecture.md` how it works: [`canton-connect`](canton-connect/architecture.md), [`canton-dappbooster`](canton-dappbooster/architecture.md), [`canton-create`](canton-create/architecture.md), [`amulet-vesting`](example-dapps/amulet-vesting/architecture.md), [`amulet-vesting-walletless`](example-dapps/amulet-vesting-walletless/architecture.md), [`token-vesting`](example-dapps/token-vesting/architecture.md) and [`token-vault`](example-dapps/token-vault/architecture.md). `canton-theme` has none: the split between components and theme is in canton-dappbooster's;
- the `CLAUDE.md` files hold the rules for writing code here. They are addressed to agents and bind humans too: [`CLAUDE.md`](CLAUDE.md) for the repo, [`example-dapps/CLAUDE.md`](example-dapps/CLAUDE.md) for every example, and one in each package for its deltas.

## Before opening a pull request
Expand Down
Loading
Loading