Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
be4f6a4
Multi-Sync Example
Viktor-Kalashnykov-da Apr 14, 2026
1cf8761
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 15, 2026
b22190a
Improvement: improved scenario
Viktor-Kalashnykov-da Apr 15, 2026
94c0bd8
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da Apr 16, 2026
03eb98c
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 16, 2026
5732849
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 16, 2026
2653b4b
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 16, 2026
2ef4f0f
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 16, 2026
65626c5
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 16, 2026
b56669f
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 17, 2026
54bf370
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 17, 2026
2fc6823
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 17, 2026
daef30d
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 17, 2026
d958743
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da Apr 17, 2026
6b2f2ff
FIxed merge conflicts for merge from main
Viktor-Kalashnykov-da Apr 17, 2026
93cc7d0
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 21, 2026
41526a7
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 21, 2026
2ccfdc9
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da Apr 21, 2026
0bef023
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 21, 2026
cf70bdb
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 21, 2026
4ffe24d
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 21, 2026
60cbf30
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da Apr 22, 2026
7fad455
CI e2e tests fix
Viktor-Kalashnykov-da Apr 22, 2026
4e2e692
Wallet sdk - multisync #31871
Viktor-Kalashnykov-da Apr 22, 2026
1b4a912
Fix: Multi sync DARs handling
Viktor-Kalashnykov-da Apr 22, 2026
23e4255
Improvement: updated information in MD file for example
Viktor-Kalashnykov-da Apr 22, 2026
2d678c1
Fix: Code Review
Viktor-Kalashnykov-da Apr 22, 2026
3995834
Fix: Code Review
Viktor-Kalashnykov-da Apr 22, 2026
60ad2a6
Fix: Code Review
Viktor-Kalashnykov-da Apr 22, 2026
ecec043
Fix: Code Review. Moving of vetting functionality to proper location
Viktor-Kalashnykov-da Apr 22, 2026
74b9a41
Code Review: refactoring + generation of Package IDs for Trade and To…
Viktor-Kalashnykov-da Apr 22, 2026
2aac57e
Fix: removed usage of zlib for package ID generation
Viktor-Kalashnykov-da Apr 22, 2026
bdf02ee
Improvement: removed DAR downloading from GitHub branch and placed th…
Viktor-Kalashnykov-da Apr 23, 2026
fa6a170
Fix: fremoved DAR uploading during bootstrapping of app synchronizer
Viktor-Kalashnykov-da Apr 23, 2026
3087e08
Improvement: removed VS Code additional settings
Viktor-Kalashnykov-da Apr 23, 2026
3efdbd8
Improvement: reverted VS Code settings
Viktor-Kalashnykov-da Apr 23, 2026
35c075e
Improvement: added layout of 3 Participant Nodes. First 2 are connect…
Viktor-Kalashnykov-da Apr 23, 2026
eb53660
Code Review: revert of openapi.yaml changes
Viktor-Kalashnykov-da Apr 23, 2026
3c32df4
Code Review: reverted changes for preferred synchronizer usage in cor…
Viktor-Kalashnykov-da Apr 23, 2026
a0c6f70
Code Review: refactoring of Preferred Synchronizer selection
Viktor-Kalashnykov-da Apr 23, 2026
a459386
Code Review: reverted logging for token-standard-service.ts
Viktor-Kalashnykov-da Apr 23, 2026
9d702fa
Code Review: improved comment for method that retrieves alias of Sync…
Viktor-Kalashnykov-da Apr 23, 2026
a3c703a
Code Review: added error handling for syncAlias() method
Viktor-Kalashnykov-da Apr 23, 2026
6f3396a
Code Review: fixed condition for checking of expected connected synch…
Viktor-Kalashnykov-da Apr 23, 2026
455ec7d
Code Review: reverted changes for example #13
Viktor-Kalashnykov-da Apr 23, 2026
e740c82
Code Review: removed unnecessary Contract namespace
Viktor-Kalashnykov-da Apr 23, 2026
955a474
Code Review: refactored DAR upload function for example #15 to not af…
Viktor-Kalashnykov-da Apr 23, 2026
02eca99
Code Review: removed separated TS targets for example #15 testing
Viktor-Kalashnykov-da Apr 23, 2026
0f45ebd
Code Review: removed not necessary targets
Viktor-Kalashnykov-da Apr 23, 2026
81db696
Improvement: separation of Multi Sync examples test from other ones
Viktor-Kalashnykov-da Apr 23, 2026
a83b5bf
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da Apr 23, 2026
679ae6a
Improvement: removed dependency on App Registry for Amulet contract h…
Viktor-Kalashnykov-da Apr 23, 2026
2b42d3d
Improvement: added multi-participant handling for scenario #15
Viktor-Kalashnykov-da Apr 24, 2026
2220904
Improvement: improved documentation for example execution
Viktor-Kalashnykov-da Apr 27, 2026
06c3a59
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da Apr 27, 2026
e042b56
Improvement: reverted changes for core upload functionality and added…
Viktor-Kalashnykov-da Apr 27, 2026
b550dc9
Improvement: improved documentation for resolvePreferredSynchronizerId()
Viktor-Kalashnykov-da Apr 27, 2026
b8b45f9
Improvement: added polling with retries for allocation requests for B…
Viktor-Kalashnykov-da Apr 27, 2026
8ec80cc
Improvement: realigned parties, PNs and Synchronizers
Viktor-Kalashnykov-da Apr 27, 2026
7165493
Code Review
Viktor-Kalashnykov-da Apr 28, 2026
43e4143
Improvement: refactoring of example and removed usage of mulit party …
Viktor-Kalashnykov-da Apr 28, 2026
879b12e
Improvement: improved comments to example
Viktor-Kalashnykov-da Apr 28, 2026
fed9509
Fix: removed unnecessary import
Viktor-Kalashnykov-da Apr 28, 2026
0b04346
Code Review: added TODO for dat.ts file
Viktor-Kalashnykov-da Apr 29, 2026
2f50e8b
Refactoring: modularization of example 15
Viktor-Kalashnykov-da Apr 29, 2026
9f29654
Refactoring: rename multi sync example folder
Viktor-Kalashnykov-da Apr 29, 2026
da1c66c
Code Review: Removed steps description from methods document for mult…
Viktor-Kalashnykov-da Apr 30, 2026
147c160
Code Review: removed usage of 'any' type in multi-sync scripts
Viktor-Kalashnykov-da Apr 30, 2026
fa552ab
Code Review: removed Trade App from app synchronizer, removed reass…
Viktor-Kalashnykov-da Apr 30, 2026
c7bfb25
Code Review
Viktor-Kalashnykov-da Apr 30, 2026
1b4935e
Potential fix for pull request finding 'Unused variable, import, func…
Viktor-Kalashnykov-da May 4, 2026
c807045
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da May 4, 2026
b003d34
FIxed package.json
Viktor-Kalashnykov-da May 4, 2026
1733b6c
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da May 5, 2026
9d82357
Increased SDK version of DAML (3.4.9 is not maintained anymore) to ve…
Viktor-Kalashnykov-da May 5, 2026
1c5b6ad
Merge branch 'main' into wiktor/multisync-example
Viktor-Kalashnykov-da May 5, 2026
8411741
Code Review: removed usage of adhoc TokenRules V1 and Trading App V1 …
Viktor-Kalashnykov-da May 5, 2026
96a8519
Code Review: refactoring of resolveSynchronizerId()
Viktor-Kalashnykov-da May 5, 2026
25f2a22
Code Review: refactor contract logging
Viktor-Kalashnykov-da May 5, 2026
6709be9
Code Review: added TODO comment for checking of vetting state inside …
Viktor-Kalashnykov-da May 5, 2026
695d386
Code Review: changed name of documentation file for multi-sync example
Viktor-Kalashnykov-da May 5, 2026
32e9df4
Potential fix for pull request finding 'Unused variable, import, func…
Viktor-Kalashnykov-da May 5, 2026
f633b32
Potential fix for pull request finding 'Unused variable, import, func…
Viktor-Kalashnykov-da May 5, 2026
8325cc3
Potential fix for pull request finding 'Unused variable, import, func…
Viktor-Kalashnykov-da May 5, 2026
c2e0e30
Fix: fixed Amulet Allocation
Viktor-Kalashnykov-da May 5, 2026
5d69aad
Code Review: refactoring
Viktor-Kalashnykov-da May 5, 2026
46f8d24
Code Review: updated README.md file for example #15
Viktor-Kalashnykov-da May 5, 2026
b0e4f16
Code Review: fixed Bob correct synchronizer assignment of Token Contr…
Viktor-Kalashnykov-da May 5, 2026
cb6f9c1
Potential fix for pull request finding 'Unused variable, import, func…
Viktor-Kalashnykov-da May 5, 2026
28a29c1
no party.ts
jarekr-da May 6, 2026
9ca212e
example 15: remove manual reassignment, rely on Canton auto-reassignment
jarekr-da May 6, 2026
6550c6f
feat: improved checkIfPartyExists
jarekr-da May 6, 2026
2c1c420
example-15: improved reassing
jarekr-da May 6, 2026
e8da61c
example-15: improved log
jarekr-da May 6, 2026
c4a3064
feat: added manual reassign
jarekr-da May 6, 2026
1e715a2
example-15: hack allows example without manual reassignment
jarekr-da May 6, 2026
00e056c
example-15: better log
jarekr-da May 6, 2026
5aa7154
example-15: removed dars
jarekr-da May 6, 2026
5ab8edc
example 15: add splice-test-token-self-transfer-v1 DAR with Token_Sel…
jarekr-da May 7, 2026
c35721a
Keep TokenRules on app-synchronizer for entire OTC flow
jarekr-da May 7, 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
11 changes: 10 additions & 1 deletion .github/actions/setup_canton/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ inputs:
instance:
description: 'Instance type: canton or localnet'
required: true
multi-sync:
description: 'Start localnet with --profile multi-sync'
required: false
default: 'false'
runs:
using: 'composite'
steps:
Expand Down Expand Up @@ -105,7 +109,12 @@ runs:
- name: Start Localnet
if: inputs.instance == 'localnet'
shell: bash
run: yarn start:localnet -- --network=${{ inputs.network }}
run: |
MULTI_SYNC_FLAG=""
if [ "${{ inputs.multi-sync }}" = "true" ]; then
MULTI_SYNC_FLAG="--multi-sync"
fi
yarn start:localnet -- --network=${{ inputs.network }} $MULTI_SYNC_FLAG

- name: Save Docker images to cache
if: ${{ inputs.instance == 'localnet' && steps.localnet-cache.outputs.cache-hit != 'true' }}
Expand Down
60 changes: 60 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,61 @@ jobs:
name: docker-logs-scripts-${{ matrix.network }}
path: logs/

wallet-sdk-scripts-e2e-multi-sync:
name: wallet-sdk-scripts-e2e-multi-sync (${{ matrix.network }})
runs-on: ubuntu-latest
needs: [build, e2e-affected]
if: needs.e2e-affected.outputs.affected_wallet_sdk == 'true'
strategy:
fail-fast: false
matrix:
network: [devnet, mainnet]

steps:
- name: Checkout
uses: actions/checkout@v6

- uses: ./.github/actions/setup_yarn

- uses: ./.github/actions/setup_canton
with:
network: ${{ matrix.network }}
instance: localnet
multi-sync: 'true'

- uses: ./.github/actions/check_resources

- name: Build project
run: yarn build:all

- name: Test multi-sync example script (${{ matrix.network }})
env:
MAX_IO_LISTENERS: '50'
run: yarn script:test:examples:multi-sync

- uses: ./.github/actions/check_resources

- name: Stop Localnet (${{ matrix.network }})
if: always()
run: yarn stop:localnet -- --network=${{ matrix.network }} --multi-sync

- name: Save container logs
if: failure()
run: |
#!/usr/bin/env bash
set -euo pipefail
mkdir -p logs
for c in $(docker ps -a --format '{{.Names}}'); do
docker logs "$c" &> "logs/$c.log" || true
done

- name: Upload logs as artifacts
if: failure()
uses: actions/upload-artifact@v7
with:
name: docker-logs-scripts-multi-sync-${{ matrix.network }}
path: logs/

test-wallet-sdk-e2e:
name: test-wallet-sdk-e2e
runs-on: ubuntu-latest
Expand All @@ -532,6 +587,7 @@ jobs:
e2e-affected,
wallet-sdk-snippets-e2e,
wallet-sdk-scripts-e2e,
wallet-sdk-scripts-e2e-multi-sync,
wallet-sdk-pkg,
]
if: always()
Expand All @@ -554,6 +610,10 @@ jobs:
echo "wallet-sdk scripts e2e was scheduled but did not succeed"
exit 1
fi
if [ "${{ needs.wallet-sdk-scripts-e2e-multi-sync.result }}" != "success" ]; then
echo "wallet-sdk scripts e2e (multi-sync) was scheduled but did not succeed"
exit 1
fi
echo "all wallet-sdk-e2e jobs passed"
else
echo "wallet-sdk e2e skipped (no affected wallet-sdk dependencies)"
Expand Down
2 changes: 1 addition & 1 deletion damljs/token-standard-models/daml.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sdk-version: 3.4.9
sdk-version: 3.4.11
build-options:
- --enable-interfaces=yes
name: token-standard-models
Expand Down
1 change: 1 addition & 0 deletions docs/wallet-integration-guide/examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"run-12": "tsx ./scripts/12-subscribe-to-events.ts | pino-pretty",
"run-13": "tsx ./scripts/13-rewards-for-deposits/index.ts | pino-pretty",
"run-14": "tsx ./scripts/14-offline-signing.ts | pino-pretty",
"run-15": "tsx ./scripts/15-multi-sync/index.ts | pino-pretty",
"stress-run-01": "tsx ./scripts/stress/01-merge-utxos.ts | pino-pretty",
"stress-run-02": "tsx ./scripts/stress/02-merge-utxos-delegate.ts | pino-pretty"
},
Expand Down
239 changes: 239 additions & 0 deletions docs/wallet-integration-guide/examples/scripts/15-multi-sync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
# Example 15: Multi-Synchronizer DvP Trade

## Overview

This example implements a Delivery vs Payment (DvP) flow across multiple
synchronizers. It demonstrates how to orchestrate a trade between Amulet
(on a global synchronizer) and a Token instrument (on a private/app
synchronizer) using the OTC Trading App.

Complete workflow covered:

- SDK initialization with multiple synchronizers
- Party allocation and registration across synchronizers
- Parallel asset minting (Amulet on global, Token on private)
- Multi-synchronizer trade settlement with multi-party signing
- Cross-synchronizer contract reassignment

## Prerequisites

### 1. Download the localnet bundle (first time only)

If you have never run localnet before, or after a Splice version update:

```bash
yarn script:fetch:localnet
```

For mainnet network variant:

```bash
yarn script:fetch:localnet -- --network=mainnet
```

This populates `.localnet/docker-compose/` and `.localnet/dars/`.

The two DARs required by this example are bundled in the same folder as the script:

| DAR file | Purpose |
| -------------------------------------------- | ---------------------------------------------------------------------------------- |
| `splice-token-test-trading-app-v2-1.0.0.dar` | `OTCTrade` and `OTCTradeAllocationRequest` templates for orchestrating the trade |
| `splice-test-token-v1-1.0.0.dar` | `Token` and `TokenRules` templates — the custom instrument on the app-synchronizer |

## Running Locally

All commands are run from the **repository root** unless noted otherwise.

### Full end-to-end (start → run → stop)

All `yarn start:localnet`, `yarn stop:localnet`, `yarn script:*` commands must be
run from the **repository root** (`splice-wallet-kernel/`).
The example script itself (`yarn run-15`) must be run from the
`docs/wallet-integration-guide/examples/` subdirectory.

```bash
# ── From the repository root ──────────────────────────────────────────────────

# Step 1: Fetch localnet bundle (first time or after a Splice version update)
yarn script:fetch:localnet
# For mainnet variant:
# yarn script:fetch:localnet -- --network=mainnet

# Step 2: Start localnet in multi-sync mode
# This spins up 16 containers: the standard 14 localnet containers plus
# multi-sync-startup (runs the app-synchronizer.sc bootstrap script, then exits)
# and multi-sync-ready (health-gate container).
yarn start:localnet -- --multi-sync
# For mainnet variant:
# yarn start:localnet -- --network=mainnet --multi-sync

# Step 3: Wait until all containers are healthy
# multi-sync-startup will appear as "Exited (0)" — that is expected and correct.
# All other containers should show "(healthy)" before you proceed.
docker ps --format "table {{.Names}}\t{{.Status}}"

# ── From docs/wallet-integration-guide/examples/ ──────────────────────────────

# Step 4: Run the example
cd docs/wallet-integration-guide/examples
yarn run-15

# ── From the repository root ──────────────────────────────────────────────────

# Step 5: Stop the multi-sync localnet when done
cd - # return to repository root
yarn stop:localnet -- --multi-sync
# For mainnet variant:
# yarn stop:localnet -- --network=mainnet --multi-sync
```

Alternatively, run the example from the repository root using the workspace shorthand:

```bash
yarn workspace docs-wallet-integration-guide-examples run-15
```

### Quick run (multi-sync localnet already running)

From `docs/wallet-integration-guide/examples/`:

```bash
cd docs/wallet-integration-guide/examples
yarn run-15
```

Or from the repository root:

```bash
yarn workspace docs-wallet-integration-guide-examples run-15
```

### Run via the dedicated multi-sync test suite

This is the same flow used in CI for the `wallet-sdk-scripts-e2e-multi-sync` job.
All commands run from the **repository root**.

```bash
# Step 1: Start multi-sync localnet
yarn start:localnet -- --multi-sync
# For mainnet variant:
# yarn start:localnet -- --network=mainnet --multi-sync

# Step 2: Run the multi-sync test suite (runs example 15 only)
yarn script:test:examples:multi-sync

# Step 3: Stop when done
yarn stop:localnet -- --multi-sync
```

### Run as part of the full example test suite

All commands run from the **repository root**.

```bash
# Ensure DARs are downloaded and multi-sync localnet is running (steps 1–3 above),
# then run the full suite (examples 01–14 + 15):
yarn script:test:examples
```

If the DARs are missing from the script folder, example 15 will fail immediately with:
`Required DAR not found`

### Expected output

```
[v1-15-multi-sync-trade] Connected synchronizers: global, app-synchronizer
[v1-15-multi-sync-trade] All required DARs uploaded successfully
[v1-15-multi-sync-trade] All DARs vetted on app-synchronizer
[v1-15-multi-sync-trade] Parties allocated — alice: ..., bob: ..., tradingApp: ...
[v1-15-multi-sync-trade] alice: registered on app-synchronizer
[v1-15-multi-sync-trade] bob: registered on app-synchronizer
[v1-15-multi-sync-trade] tradingApp: registered on app-synchronizer
[v1-15-multi-sync-trade] Alice: Amulet holding minted (2,000,000)
[v1-15-multi-sync-trade] TokenRules created by Bob (on app-synchronizer)
[v1-15-multi-sync-trade] Bob: Token holding minted (500 TestToken, on app-synchronizer)
[v1-15-multi-sync-trade] OTCTrade created by Trading App
[v1-15-multi-sync-trade] Trading App: Allocation requests created
[v1-15-multi-sync-trade] Alice: Amulet allocation created for leg-0
[v1-15-multi-sync-trade] Bob: TestToken allocation created for leg-1 (on app-synchronizer)
[v1-15-multi-sync-trade] Trading App: OTCTrade settled
[v1-15-multi-sync-trade] Alice: TestToken self-transferred on app-synchronizer
[v1-15-multi-sync-trade] Final contract state after step 12 (Transfer): ...
```

## How it Works

| Step | Who | What | Synchronizer |
| ---- | ----------- | ----------------------------------------------------------- | ------------ |
| 1 | — | Create SDKs (P1, P2, P3) and discover synchronizers | global + app |
| 2 | — | Vet DARs on all synchronizers and all participants | global + app |
| 3 | — | Allocate parties (Alice/P1, Bob/P2, TradingApp/P3) | global |
| 4 | — | Discover Token interface on app synchronizer | app |
| 5 | Alice | Mint 2,000,000 Amulet for Alice | global |
| 6a | Bob | Create `TokenRules` contract | app |
| 6b | Bob | Mint 500 `TestToken` holding | app |
| 6c | Bob | Reassign `TokenRules` + `Token` to global-domain | app → global |
| 7a | Alice | Create `OTCTradeProposal` (2 legs) | global |
| 7b | Bob | `OTCTradeProposal_Accept` | global |
| 7c | Trading App | `OTCTradeProposal_InitiateSettlement` → `OTCTrade` created | global |
| 8 | — | Read `OTCTrade` contract ID | global |
| 9 | Alice | `AllocationFactory_Allocate` (Amulet, leg-0) | global |
| 10 | Bob | `AllocationFactory_Allocate` (TestToken, leg-1) | global |
| 11a | — | Locate Bob's TestToken allocation | global |
| 11b | Trading App | `OTCTrade_Settle` (multi-party signing) | global |
| 11c | Bob + Alice | Reassign `TokenRules` + Alice's `Token` to app-synchronizer | global → app |
| 12 | Alice | `TransferFactory_Transfer` self-transfer | app |

## Troubleshooting

### `Required DAR not found`

Verify the DAR files are present in the script folder:

```bash
ls -la docs/wallet-integration-guide/examples/scripts/15-multi-sync/splice-token-test-trading-app-v2-1.0.0.dar \
docs/wallet-integration-guide/examples/scripts/15-multi-sync/splice-test-token-v1-1.0.0.dar
```

### `App synchronizer not found (alias: app-synchronizer)`

This error means the `app-user` participant is not connected to the app-synchronizer.
The `scripts/localnet/app-synchronizer.sc` bootstrap script must connect **both**
`app-provider` and `app-user` to the app-synchronizer. Check that you are using
the current version of that file (it should reference both participants).

Check that the `multi-sync-startup` bootstrap container ran to completion:

```bash
docker logs $(docker ps -a --filter name=multi-sync-startup --format "{{.ID}}")
```

The last line should read:

```
app-synchronizer bootstrap with package vetting completed successfully for app-provider and app-user
```

If localnet was started with an older version of the bootstrap script, restart it:

```bash
yarn stop:localnet -- --multi-sync
yarn start:localnet -- --multi-sync
```

### `No connected synchronizers found`

Localnet may still be initialising. Wait until all containers show `(healthy)`:

```bash
docker ps --format "table {{.Names}}\t{{.Status}}"
```

### Docker containers not starting

Ensure Docker Desktop has enough resources (≥ 8 GB RAM, ≥ 4 CPUs recommended).
Check current usage:

```bash
docker stats --no-stream
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

/**
* Multi-synchronizer localnet participant configuration.
*
* Port layout (PARTICIPANT_JSON_API_PORT_SUFFIX = 975):
* 2975 — app-user (P1): global + app-synchronizer
* 3975 — app-provider (P2): global + app-synchronizer
* 4975 — sv (P3): global + app-synchronizer
*
*/

// bob-participant JSON API (3 + PARTICIPANT_JSON_API_PORT_SUFFIX 975)
export const LOCALNET_BOB_LEDGER_URL = new URL('http://localhost:3975')

// trading-app-participant JSON API (4 + PARTICIPANT_JSON_API_PORT_SUFFIX 975)
export const LOCALNET_TRADING_APP_LEDGER_URL = new URL('http://localhost:4975')
Loading
Loading