Canton C++ SDK
| Field | Value |
|---|
| Organization | Equilibrium (equilibrium.co) |
| Author / Primary Contact | Olli Tiainen o***@equilibrium.co |
| Status | Submitted |
| Created | 2026-08-31 |
| Proposal Type | RFP-aligned |
| RFP / Roadmap Area | RFP #17: SDKs in different languages |
| Champion | Heslin Kim, Zenith (@heslin-zenith) |
| Total Funding Request | Up to 3,967,000 CC plus the separate security-review pass-through |
| License | Apache-2.0, all deliverables (see 2.14) |
| Project Duration | ~4 months engineering (6-month hard deadline); production adoption open to month 14, retention and expansion to month 20 |
| Label | canton-apis |
Table of Contents
Abstract
Equilibrium proposes the Canton C++ SDK, an Apache-2.0 library family that gives native C++ applications typed Ledger API v2 access without adding a JVM or sidecar to their runtime path.
| Deliverable | Published form |
|---|
| Canton C++ libraries | canton-cpp-sdk with six canton::* CMake targets |
| Canton C++ code generation | canton-codegen-cpp, shipped as a dpm codegen-cpp component |
| Canton C++ verification and adoption artifacts | canton-conformance-cpp, canton-bench-cpp, canton-reference-cpp and versioned documentation |
Engineering delivery is estimated at four months, with a hard deadline of six months. Production adoption remains open until month 14; retention and expansion run through month 20 under Milestone 5. The base grant assigns 45 percent to engineering and 55 percent to adoption outcomes. A security-review pass-through is separate. The amounts are described in detail in Funding section.
Equilibrium brings an established C++ practice, recent work on a post-quantum
signature path in a C++ ledger reference client, and grant-funded SDK work in other
ecosystems.
Motivation
The missing client
A C++ team can find Ledger API protobuf definitions, an OpenAPI document, and SDKs
for Java, TypeScript, Rust, Go, Python and C#. It cannot find a maintained C or C++
SDK that supplies the application-level client behaviour above generated gRPC stubs.
Building directly on the protos still leaves the application layer to implement.
That includes Daml-LF decoding, serialization for every generated record, variant
and enum, change-ID deduplication, command recovery, resumable streams and
reassignment semantics. A sidecar in a supported language avoids some of that work,
but adds a process boundary and a second toolchain. It also splits the signing path.
Appendix A lists what
generated gRPC stubs do not provide.
The signing path matters because PKCS #11, the standard HSM API, is specified in
ANSI C. A Securosys driver already ships in the Canton wallet repository. The SDK
defines a native C++ signer boundary for interactive submission without putting
another runtime between the application and its keys. Vendor-specific HSM and KMS
drivers remain outside v1.
Why C++ now
Digital Asset maintains Java and TypeScript SDKs. The Fund has approved Rust (#407),
Go and Python DAZL (#38) and C#/.NET (#46), and a Swift/Kotlin mobile SDK (#574) is
currently in voting. Its SDK request leaves C++ and Scala without a fully featured SDK. We found no C++ SDK or
open C++ proposal in the Fund repository.
Scala applications can use the maintained Java SDK on the JVM. C++ applications
have no equivalent fallback and must cross a process boundary to use a supported
runtime. That gap sits close to two parts of Canton's institutional market where
native integration matters: trading systems and key-management hardware.
Who benefits
Digital Asset's 2025 funding round included Tradeweb Markets, Citadel Securities,
Optiver, IMC and Virtu Financial. Its 2024 network pilot included Cboe Global
Markets, IEX, Baymarkets and DTCC. Commercial direct-market-access products for this
market are already distributed as C++ libraries, and PKCS #11 specifies an ANSI C
interface to HSMs. Sources are listed in
Appendix C.
Specification
1. Objective
A C++ application team can generate typed Daml bindings and build, sign, submit,
stream and query Canton Ledger API v2 workflows through one maintained native SDK,
without adding a JVM or sidecar to the application runtime.
2. Implementation Mechanics
2.1 Deliverables & scope
The Canton C++ SDK gives C++ applications typed access to commands, ledger state,
update streams, token workflows and external signing. Milestone 1 will publish the
conformance matrix in 2.15, mapped to the supplied Ledger Client Standard.
Named release outputs:
| Output | Published form |
|---|
| Canton C++ SDK | canton-cpp-sdk repository |
| Canton C++ libraries | canton::core, canton::ledger, canton::admin, canton::auth, canton::token, canton::pqs |
| Canton C++ code generator | canton-codegen-cpp and dpm codegen-cpp |
| Canton C++ conformance suite | canton-conformance-cpp, with release results under conformance/results/ |
| Canton C++ benchmark suite | canton-bench-cpp, with release results under benchmarks/results/ |
| Canton C++ compatibility matrix | COMPATIBILITY.md |
| Canton C++ reference application | canton-reference-cpp |
| Canton C++ documentation | Versioned site generated from docs/ |
| Canton C++ support policy | docs/support.md |
| Canton C++ upgrade playbook | docs/upgrade-playbook.md |
V1 includes:
- Core libraries. A modular family (
canton::core, canton::ledger,
canton::admin, canton::auth, canton::token, canton::pqs) for the transaction,
state, update and admin services listed below, with JWT/OIDC authentication and
TLS/mTLS on every transport.
- Code generation.
canton-codegen-cpp generates typed C++ from .dar files
(all serializable Daml types, templates, choices, interfaces, contract keys and
dependencies, see 2.4), with both gRPC and
JSON codecs on generated types.
- Token workflows. CIP-0056 transfers and allocation-based settlement, and
CIP-0112 V2 accounts, revised allocations and holding-change events, including
choice-context resolution and disclosed-contract handling.
- External signing. Prepare/execute flows with a pluggable signer interface, a
software signer and an out-of-process reference signer (2.8). Vendor HSM and KMS
drivers can implement the same interface but are outside v1.
- PQS access. A typed client for an existing Participant Query Store database,
wrapping its SQL API and decoding payloads into generated C++ types (2.9).
- Resilient streams. Resumable update and completion streams, command
recovery through the completion service, same-Participant change-ID deduplication,
and multi-synchronizer reassignment events surfaced as their two constituent
events. The SDK mirrors the maturity label of the corresponding Canton release.
- Observability. SDK-level client tracing and metrics with W3C trace-context
propagation, including retries, reconnects and command recovery (2.10).
- Conformance. A test suite that exercises the SDK on LocalNet and DevNet against
the v1 conformance matrix and explicitly agreed deviations in 2.15.
- Benchmarks. A reproducible suite for command submission
round-trips and update-stream throughput, with methodology and environment stated,
rerun and republished per release.
- Documentation and maintenance. Versioned documentation as described in 2.16,
a compatibility matrix and semantic versioning.
Out of scope for v1 (roadmapped, not excluded):
- Package administration. DAR upload, validation and vetting/unvetting remain
with existing tools such as
dpm. Package metadata and resolution needed for
Ledger API and SCU operation remain internal implementation details.
- Topology writes. Constructing and submitting topology transactions.
- Topology-event subscriptions. V1 covers topology reads only.
- Multi-synchronizer management. Listing, per-synchronizer vetting and target
selection. V1 surfaces multi-synchronizer events under the maturity label assigned
by the supported Canton release.
- In-memory ACS. An active contract set kept current from the update
stream.
- High-availability features. Command batching, pending-set tracking,
cross-participant deduplication, stream
failover and node-health monitoring for high-availability deployments.
- WASM and browser targets. These remain roadmap items.
- Stable C ABI. A later C ABI can serve HSM firmware, native extensions, Swift
and legacy C estates once the C++ API has settled.
- Vendor HSM and KMS drivers. V1 publishes and tests the signer interface, a
software signer and an out-of-process reference signer, but no vendor-specific
driver.
We will sequence the remaining roadmap with the canton-apis SIG once v1 adoption
data exists.
Out of scope entirely: wallet user interfaces, Daml authoring tools, any
alternative runtime or node implementation.
2.2 Canton C++ SDK Sources
The protobuf definitions in digital-asset/canton are the source of truth. The SDK
vendors and pins both:
- the
community/ledger-api-proto module at the pinned Canton release (named
community/ledger-api on the 3.3 and 3.4 release lines), covering
com/daml/ledger/api/v2/** including admin/ and interactive/, plus the
separately housed value protos; and
community/base/src/main/protobuf/com/digitalasset/canton/topology/admin/v30/**,
including TopologyManagerReadService, together with the Canton protobufs that
tree imports.
Both roots and their imports are pinned to the same Canton release. The initial
implementation target is Canton 3.5.15, the latest published release checked on
2026-08-28. Supporting a new Canton range triggers re-vendoring in an SDK minor
release and an architecture decision record. The approved Rust SDK uses the same
model.
COMPATIBILITY.md publishes one row per exact SDK and Canton patch-release pair. A
pair is not labelled tested until its result file exists. Before the first SDK
release, the matrix contains no release rows. Each published row follows these rules:
Support | Required Canton release | Required Contract-key semantics | Required Hash-scheme version | Required Conformance results |
|---|
tested | Exact patch release | Observed behavior for that release, including uniqueness and negative-lookup validation | Hash-scheme version implemented for that release | Existing result file for the pair |
untested | Exact patch release | not claimed | Hash-scheme version implemented for that release | none |
unsupported | Exact patch release | unavailable | unavailable | none |
The JSON Ledger API is a secondary transport. It uses the Daml-LF JSON encoding in
the participant's OpenAPI document, not proto3 canonical JSON, so protobuf JSON
utilities cannot be reused. The published OpenAPI specification also contains
structures that should not become public SDK types, including duplicated schemas and
untyped payloads. We therefore generate from protos and hand-write thin clients for
the small set of JSON-only endpoints, JSON Ledger API create/exercise submission
and ACS queries.
2.3 canton::* Library Family
The six libraries are layered so dependencies point downwards:
canton::core: values, offsets, errors, retry policy, configuration.
canton::ledger: command submission (sync, async and coroutines), update service, state
service, event and contract queries, version service.
canton::admin: party and user management, identity provider
configuration, pruning, topology read.
canton::auth: token providers (static bearer, OIDC client-credentials with
caching and refresh), designed so custom providers plug in.
canton::token: token standard workflows over generated interface types.
canton::pqs: typed read-side queries against a Participant Query Store.
The conformance matrix in 2.15 enumerates the Ledger API and Admin API services
covered by these libraries. Core utilities cover value handling, offsets, error
classification, retries and configuration; the v1 exclusions in 2.1 still apply.
These names are both exported CMake targets and C++ namespaces. Their installable
package artifacts use the corresponding hyphenated names: canton-core,
canton-ledger, canton-admin, canton-auth, canton-token and canton-pqs.
Transport uses the gRPC C++ callback API. JSON and gRPC errors are classified as
retriable or non-retriable and retain the details returned by the Ledger API, including error
codes, messages, request info, error info and structured contract/package/party
identifiers. HSM-, KMS- and file-backed keys plug into one signer interface,
following the driver split used by
the Canton wallet SDK.
Public gRPC operations for submissions, reads, streams and the included admin
utilities offer synchronous, callback-based asynchronous and C++20 coroutine
interfaces over the same transport. V1 supports one documented executor model,
with shared cancellation, deadline and error handling.
2.4 canton-codegen-cpp
canton-codegen-cpp reads a .dar, resolves its transitive Daml-LF dependencies,
and emits typed C++ for all serializable Daml types, templates, choices, interfaces,
views and contract keys. It also emits the Ledger API's exercise-by-key and
key-prefetch paths. Because platform
support for contract keys varies by Canton release, COMPATIBILITY.md records the
semantics of each exact release pair. For the initial Canton 3.5.15 target, that means
non-unique keys and no validation of negative key lookups. A tested label therefore
does not imply key uniqueness. Platform key support does not gate a milestone.
Daml-LF decoding happens at code-generation time through a project-owned thin JVM
adapter to the public daml-lf-archive interface. Generated code and runtime
libraries have no JVM dependency. The funded C# (#46) and Rust (#407) SDKs use the
same approach. A compatible
shared component can be considered later during maintenance.
The Daml compiler checks smart contract upgrade compatibility at build time. The
participant applies the relevant checks at DAR upload and runtime. A package version
bump regenerates the corresponding C++ types. The SDK supports a coordinated v3 to
v4 rollout as follows:
- Generated versions coexist. Version-disambiguated C++ namespaces and symbols
allow v3 and v4 bindings from the same Daml package to link into one application.
Both generated choice APIs remain available during the rollout.
Codegen configuration maps individual package versions to user-selected C++
namespaces, so
da::v1::Template and da::v2::Template can coexist. The generator
rejects mappings that produce symbol collisions. Namespace selection does not
change the SCU compatibility rules below.
- Read compatibility. Ledger API events identify their source package and carry
payloads encoded for that version. The SDK dispatches by package identity and
applies SCU-compatible upgrade/downgrade conversions before constructing the
requested C++ type, including for choice results. For example, a v4 binding reads
a v3 contract with a newly added optional field set to
std::nullopt. The
conversion happens in the client; the raw event does not contain the v4 field.
A v3 binding can read downgrade-compatible v4 data. These are the consuming-client
responsibilities described in Digital Asset's
Smart Contract Upgrade documentation.
- Explicit cutover. Commands use by-package-name references and expose
package_id_selection_preference. The application keeps v3 explicitly selected
after v4 is uploaded and vetted, then switches its generated choice API and
package preference to v4 at a coordinated signal. The preference covers all
packages used by the application's commands and possible interface instances.
GetPreferredPackages can discover a vetted package set; the SDK does not switch
application behaviour merely because a newer DAR appears.
2.5 canton-codegen-cpp Type Mapping
The mappings that need explicit SDK behaviour are:
| Daml-LF | C++ | Note |
|---|
Numeric n | canton::Numeric (integer mantissa plus scale) | LF allows 38 significant digits. No standard C++ decimal type is sufficient, so the SDK ships a fixed-point type with checked arithmetic; the C# SDK ships a fixed-point type for the same reason. |
GenMap k v | std::map with an LF value-ordering comparator | LF maps use built-in value ordering; a hash map would change both key semantics and iteration order. |
Optional a | std::optional<T> | |
| Variants | std::variant with visitor helpers | |
| Enums | closed enum class types | |
Time | canton::Timestamp | Microsecond precision, UTC. |
Party | canton::Party | Strong typedef, not a raw string. |
ContractId t | canton::ContractId<T> | Strong typedef, not a raw string. |
Because C++20 has no standard derive macros, the generator emits JSON codecs for each
record, variant and enum, together with round-trip tests.
Normalization maps gRPC, JSON and PQS payloads into the same generated C++ types,
preserving the Daml-LF value semantics described above.
2.6 canton::ledger Commands and Streams
canton::ledger implements the command and stream semantics common to the funded
SDK scopes, subject to the conformance reconciliation in 2.15:
- Command construction and submission. Typed create and exercise commands are
constructed and submitted over both gRPC and the JSON Ledger API.
- Deduplication. Change ID (acting parties, user ID, command ID) applied on
both transports. Duplicate-command rejection is guaranteed only when the retry is
sent to the same Participant.
- Command recovery. The completion service is checked after a client or participant
crash, lost connection or timeout. Participant-crash recovery reconnects to the
same Participant after restart with its ledger state retained. The SDK does not
resubmit a command before checking completions for it.
- Resumable streams. Update and completion subscriptions resume from a persisted
offset, and active-contract reads compose with update streams at a consistent
ledger offset. gRPC subscriptions support party, template and interface filters
and decode interface views into generated C++ types.
- Multi-synchronizer events. Reassignments are surfaced as their two constituent
events (unassigned on the source synchronizer, assigned on the target), never
collapsed.
COMPATIBILITY.md mirrors the upstream maturity level for each pinned
release, starting with the initial Canton 3.5.15 target.
- Retries. Retriable errors use bounded retries and configurable timeouts.
V1 recovery reconnects to the same Participant and resumes from its persisted
offsets. Automatic selection of another node and recovery across Participants
hosting the same parties remain part of the high-availability roadmap in 2.1.
2.7 canton::token
canton::token resolves transfer and allocation factories, fetches
createdEventBlob disclosures, assembles choice context, and exercises CIP-0056 and
CIP-0112 choices. Transfer pre-approvals use the published Splice wallet endpoints.
This includes one-step transfers where supported by the token implementation,
including immediate settlement to pre-approved receivers.
Registry calls use the Splice OpenAPI definitions and only the *-external
endpoints covered by their compatibility guarantee.
2.8 canton::ledger Interactive Submission
Interactive submission follows prepare, sign and execute. The canton::Signer
interface keeps HSM, KMS and air-gapped key handling outside the SDK. V1 ships a
software signer and an out-of-process reference signer under
examples/external-signing/reference-signer/. The reference signer implements
canton::Signer outside the SDK process: it receives the recomputed transaction
hash, signs with a test software key and returns the signature. It exercises
serialization, timeouts and error handling across the same process boundary used
by an HSM/KMS integration. It is neither an HSM emulator nor a production signer.
Because topology writes are outside v1, external parties must already be onboarded
or use a separate onboarding tool.
The interactive submission service requires the client to recompute the transaction
hash: when the preparing participant is not trusted, the client hashes the raw
transaction itself instead of signing the hash the participant returns. canton::Signer
receives only that recomputed hash, not the value from the prepare response. For
externally signed transactions, the hash also covers the synchronizer ID.
The hashing scheme is versioned and changes between Canton releases, so the SDK pins
a scheme version to each Canton release. The SDK's v1 release pins scheme V2/V3, the
stable scheme on the 3.5.x line after Canton 3.3 dropped V1, and excludes V4, which
is still Dev-protocol only. COMPATIBILITY.md lists the hash-scheme version next to
contract-key semantics for every release pair, because buf breaking-change
detection does not flag a scheme change. The exact per-release set is settled at
Milestone 1.
2.9 canton::pqs
Digital Asset's Participant Query Store (PQS) is a separate component that ingests
participant ledger data into PostgreSQL and exposes it through a SQL API.
canton::pqs is a C++ client for an existing PQS database. It wraps the
PQS SQL API
for active contracts, creates, archives, exercises and offset handling in typed
query builders, and uses the generated JSON codecs to decode contract payloads into
the same C++ types used by the rest of the SDK. PQS is Apache-2.0
(digital-asset/participant-query-store, checked 2026-08-20). The client does not
maintain a second in-process copy of ledger state.
For example, an application generates Iou bindings from its DAR, connects to an
existing PQS database using the operator's connection settings, and selects the
owner party. Its typed query is:
pqs.active<Iou>().where(Iou::column::owner == party)
On execution, the query builder runs the SQL query and decodes the returned
contract payloads into Iou values. The application does not write SQL or manually
decode JSON. This illustrates the proposed query API.
The SDK does not install or operate PQS. Deployment and operation of PQS/PostgreSQL,
including the database endpoint, credentials and TLS policy, remain the operator's
responsibility.
2.10 Canton C++ SDK Observability
Canton already provides node-side OpenTelemetry support and
W3C trace-context propagation,
and PQS preserves the ledger trace context.
A C++ application can instrument itself directly with opentelemetry-cpp.
The missing part is SDK-level client instrumentation: each application would
otherwise have to instrument Ledger API calls and context propagation itself,
including the client's retries, stream reconnects, recovery after ambiguous
submissions and submit-to-completion handling.
The SDK exports traces and metrics through opentelemetry-cpp and OTLP. It adds
spans around Ledger API operations and stream lifecycles, propagates the caller's
W3C trace context over gRPC and JSON, counts requests and responses by endpoint and
outcome, and records client metrics for request latency, retries, reconnects,
recovery and submit-to-completion latency. This
correlates application requests with participant-side traces and exposes the
client's internal operations. It also logs structured Ledger API errors. Log level,
format and destination are configurable.
Request/response logging includes trace IDs and redacts credentials; structured
Ledger API error details are available at verbose log levels. Trace IDs are created
when no caller context exists, injected into requests and extracted from responses
when supplied, on both gRPC and JSON transports.
The documentation lists metric names, units and labels, including latency
histograms and call and error counters. Generated template and choice metadata
supports contract-specific instrumentation, with configurable limits on metric
label cardinality. Contract IDs and payloads are not included in metric labels.
2.11 Canton C++ SDK Packaging
C++ has no single package manager, so the SDK ships through four channels:
- CMake
FetchContent and find_package support from the repository, with no
package-registry dependency for the SDK itself.
- A Conan recipe, published to a maintained public remote.
- A vcpkg overlay port maintained in the repository, with submission to the central
vcpkg registry pursued in parallel.
- A
dpm component (codegen-cpp) packaging the code generator, so Canton
developers invoke it the same way as the Java, JS, Rust and C# generators.
Acceptance covers items 1 through 3 and a dpm component installable from our
published recipe. Central registry listings and inclusion in Digital Asset's dpm
assembly manifest will be pursued but do not gate payment.
Milestone 1 asks the Foundation to confirm the canton:: namespace and canton-*
package names. Until then, packages use the equilibrium-canton-* prefix. The
approved Rust SDK follows the same process.
2.12 Canton C++ SDK Target Platforms and Toolchains
V1 uses C++20 and accepts against this initial matrix:
| Runner | Architecture | Compiler | Support tier |
|---|
| Ubuntu 22.04 | x86-64 | GCC 11 | Tier 1: production |
| Ubuntu 22.04 | x86-64 | Clang 14 | Tier 1: production |
| Ubuntu 24.04 | arm64 | GCC 13 | Tier 1: production |
| Ubuntu 24.04 | arm64 | Clang 18 | Tier 1: production |
| Windows Server 2022 | x86-64 | MSVC 19.40 (Visual Studio 2022 17.10) | Tier 2: development only |
| macOS 14 | arm64 | Apple Clang 15 | Tier 2: development only |
Tier 1 Linux targets receive full integration and acceptance coverage. Tier 2
Windows and macOS targets receive build, codegen and unit-test coverage in CI so
developers can build and test on their normal machines. They are not
production-supported. COMPATIBILITY.md and docs/support.md record these tiers.
CI records the compiler patch version and dependency lockfile with each result.
Changing a matrix row before v1 requires a public architecture decision record and
Foundation approval. Runtime dependencies are gRPC/protobuf, an HTTP/WebSocket
library, opentelemetry-cpp, libpq and a JWT library.
2.13 canton-conformance-cpp and Memory Safety
The SDK decodes untrusted network data and prepares payloads for signing, so memory
safety is part of the deliverable. The following checks run in CI, and the review in
Appendix B covers each decoder boundary.
- Modern C++ rules. RAII throughout, no owning raw pointers,
clang-tidy and compiler warnings as errors.
- Sanitizers. AddressSanitizer, UndefinedBehaviorSanitizer and ThreadSanitizer.
- Fuzzing. Continuous fuzzing of every decoder boundary (LF JSON codec, stream
frame handling, completion parsing) with libFuzzer corpora in the repository.
- Two test tiers. "No-node" tests (unit tests,
in-process gRPC and WebSocket mock servers, TLS handshakes, wire-shape assertions)
always run. Live integration tests against LocalNet and DevNet are gated on
environment configuration.
- Reusable fixtures. Published fixtures under
tests/fixtures/ let applications
test generated bindings against mock gRPC services with scripted ACS snapshots,
updates, completions and disconnects. A documented example uses these fixtures
and runs against LocalNet for end-to-end verification, within the platform
coverage in 2.12.
- Coverage. At least 80 percent on codegen and serialization paths, measured in CI.
- Independent review. A third-party security review at Milestone 3, budgeted as
a pass-through cost.
2.14 Canton C++ SDK Repository Practices
The public canton-cpp-sdk repository will use Apache-2.0 from day one. Releases use
semantic versioning, changelogs and migration notes. Issues and PRs are public. The
upgrade procedure lives in docs/upgrade-playbook.md. We will offer to transfer the
repository to the Foundation if adoption warrants it.
2.15 Ledger Client Standard Mapping and Phased Conformance
Digital Asset's "Ledger Client Standard" is the conformance target cited in the
funded Rust SDK proposal (#407).
The supplied copy (date/version not specified) is the baseline for this mapping.
V1 is a phased implementation of the Standard, with the current scope in 2.1
and the deviations below subject to explicit Foundation agreement at Milestone 1.
| Standard domain | V1 coverage under the current scope | Deviations and limits |
|---|
| Codegen and bindings | All serializable Daml types, templates, choices, interfaces, views, contract keys and dependencies; gRPC/JSON codecs and typed PQS access (2.4–2.5, 2.9). | Binding coverage is limited to the wrappers specified in those sections. |
| Basic infrastructure | TLS/mTLS, JWT/OIDC, error classification, bounded retries, tracing, metrics, logging and the signer interface (2.3, 2.6, 2.8, 2.10). | Node-health monitoring and vendor HSM/KMS drivers are deferred; signing coverage is as specified in 2.8. |
| Commands | Create/exercise submission over gRPC and JSON, same-Participant deduplication, completion-based recovery, exercise-by-key, key prefetch, disclosure and package selection (2.4, 2.6–2.8). | Batching and pending-set tracking are deferred. Endpoint variants and recovery scenarios are limited to the stated scope. |
| Streams | ACS reads, update/completion streams, gRPC party/template/interface filters and interface-view processing, and persisted-offset recovery (2.6). | Topology events and in-memory ACS are deferred. Paging, reverse-order retrieval and other resume mechanisms are not committed in v1. |
| Parties | Party management through the included admin services (2.3). | External-party onboarding and topology modifications remain outside v1 (2.1, 2.8). |
| Packages | Command package preference and internal package metadata/resolution (2.1, 2.4). | DAR upload, validation and vetting are deferred; a full public package-management surface is not committed in v1. |
| Topology | Topology reads through TopologyManagerReadService (2.2–2.3). | Topology construction, signing, submission and write-based mapping management are deferred. |
| User | User management through the included admin services (2.3). | Traffic computation is not committed in v1. |
| Multi-synchronizer | Separate assign/unassign events (2.6). | Listing, per-synchronizer vetting and target selection are deferred; automatic event reordering and current-state reconstruction are not committed in v1. |
| Token Standard | CIP-0056 and CIP-0112 workflows, transfers including one-step settlement, allocations, pre-approvals, choice context and disclosures (2.7, Milestone 3). | Coverage is limited to the stated workflows; instrument inspection is not committed in v1. |
| Documentation | Versioned guides, API reference and executable examples (2.16). | Documentation covers the delivered v1 scope. |
The Standard's upcoming rows—command HA, stream HA, topology through the Ledger
API, and traffic-account listing/inspection, selection and top-up—are not v1
commitments. Existing-functionality deviations remain distinct from these upcoming
rows. Mapping a domain above does not claim every row or subrequirement in that
domain; coverage remains bounded by the referenced scope and acceptance checks.
canton-conformance-cpp uses a matrix mapped to the supplied Standard and the
agreed v1 scope. It covers codegen, transport,
authentication, errors, retries, command recovery, signing, streams,
admin operations, read-side queries and token workflows. Each claimed capability
runs on LocalNet and DevNet, subject to the V2 token environment described in
Milestone 3, with results published per release. Capability rows use this form:
| ID | Capability | Pass condition | Standard row |
|---|
commands.dedup.change-id | Change-ID deduplication on both transports | A resubmission to the same Participant with the same acting parties, user ID and command ID inside the deduplication window is rejected as a duplicate and creates no second transaction. | Commands — Deduplication |
streams.update.resume | Update-stream resume from a persisted offset | A client restarted mid-stream resumes from its stored offset with no gap and no duplicate events. | Streams — Resilient streams (offset recovery) |
canton-conformance-cpp is this SDK's own acceptance gate. It aligns to the Rust
SDK's capability mapping (#407) and consumes the transaction-hashing test vectors
proposed in #617 rather than defining a competing standard. Its capability
definitions and vectors are kept separate from the C++ driver, so the SDK can be
re-verified independently of any one release.
At Milestone 1 we publish the row-level mapping and record the Foundation's explicit
agreement to the v1 deviations in reports/ledger-client-standard.md. Each row
identifies its v1 coverage, partial or deferred behavior, release constraints and
acceptance checks. Passing the suite establishes conformance to that agreed v1
scope; it does not establish full Standard coverage. Extensions selected under
Milestones 4–5 are recorded in the same mapping with their acceptance checks.
Other scope expansion requires separate agreement.
2.16 Documentation
The documentation will be a versioned site built from the repository and released
alongside the SDK. It will include:
- API reference generated from the public C++ headers;
- getting-started guides for CMake, Conan and vcpkg;
- a codegen guide with the Daml-LF to C++ type mapping;
- guides for authentication, command submission and recovery, resumable streams,
external signing, Token Standard workflows and PQS queries;
- Smart Contract Upgrade and version-migration guidance;
- a runnable example under
examples/ for each major workflow;
COMPATIBILITY.md covering Canton/Daml SDK versions, SDK versions and supported
platforms;
docs/support.md covering support windows, response targets and the production
and development support tiers in 2.12; and
docs/upgrade-playbook.md explaining how to move an application between Canton
and SDK versions.
3. Architectural Alignment
The Canton C++ SDK extends the existing Canton client stack through published API
surfaces.
- Ledger API v2 as the contract. The SDK is a client of the published protobuf
and OpenAPI surfaces, pinned per Canton release. The V1 critical path is contained
in the new client repository.
- The SDK family. Approved grants cover Rust (#407), Go (#38) and C#/.NET (#46).
Digital Asset maintains Java and TypeScript, with TypeScript dApp and wallet kits
under #69. This SDK follows their core patterns: pinned protos, JVM-assisted
codegen and a protos-first transport strategy.
- Standards. Token standard per CIP-0056 and CIP-0112. Interactive submission per
the Ledger API's interactive service. Wallet-adjacent flows compose with the
Splice wallet APIs rather than duplicating them.
- Distribution through dpm. The code generator ships as a dpm component alongside
other Canton SDK generators.
- Coordination. We will work in the canton-apis SIG, coordinate with Digital
Asset's SDK maintainers and publish the JVM adapter for reuse by other SDK teams.
- Equilibrium's other Fund proposals. We have other proposals in different areas.
None shares a deliverable, repository or budget line with this SDK, and none of
the engineers named in Why Equilibrium is committed to a grant that would run alongside it.
4. Backward Compatibility
The Canton C++ SDK is an additive client artifact. It leaves existing systems,
integrations and workflows unchanged.
Milestones and Deliverables
The delivery team is three senior C++ engineers with part-time QA and developer
relations support. Dates run from grant approval. Milestones 1 through 3 are checked
against published artifacts and demonstrations. Milestone 4 pays for third-party
production adoption. Milestone 5 pays for sustained use, upgrades, expansion and
additional production applications.
Delivery Preconditions
| Dependency | Needed by | Treatment if unavailable |
|---|
| Security-review pass-through approved and an independent reviewer booked | Milestone 3 | Equilibrium books the reviewer by Milestone 2 acceptance. A later committee approval or reviewer start date moves only the external-review check. |
| Adopter access and permission to publish evidence or attest privately | Milestones 4–5 | No adoption outcome earns a tranche until the Foundation receives the specified evidence. |
Equilibrium will source DevNet access, credentials and test parties. These are
delivery responsibilities, not Foundation dependencies, and do not defer acceptance
checks or milestone deadlines. The token test environments are described in
Milestone 3.
Hard deadlines still apply to every artifact and check within
Equilibrium's control; the external-review check is treated as stated in the table.
Milestone 1: canton::core, canton::ledger, canton::auth and Proof of Concept
- Estimated delivery: Month 1.5. Hard deadline: 2 months from grant approval.
- Estimated effort: ~50 person-days.
- Focus: Validate core feasibility and deliver a usable client early.
- Deliverables:
canton::core, canton::ledger and canton::auth: command submission
(sync/async/coroutines), update and completion streams with resume, state service reads,
JWT/OIDC auth, TLS/mTLS, retry and error classification.
- Vendored protos pinned to a named Canton release, with
COMPATIBILITY.md v1.
- OpenTelemetry tracing and metrics.
examples/localnet-poc/, submitting and reading a transaction end to end on
LocalNet and DevNet.
- First tagged release,
docs/quickstart.md, and CI (build matrix, sanitizers,
no-node tests).
reports/ledger-client-standard.md reconciliation report (2.15).
- Namespace confirmation requested from the Foundation for the
canton:: C++
namespace and the canton-* package names (2.11).
- Acceptance checks:
- The release builds on every row in the platform matrix in 2.12.
- Unit, sanitizer and no-node integration tests pass in CI.
- Submit, read state and consume updates through each execution interface in 2.3;
verify cancellation and deadline handling.
- A scripted disconnect resumes the update stream from its persisted offset on
the same Participant; a lost submission response triggers completion recovery
before any resubmission.
Repeat completion recovery after a restart of the same Participant with retained
ledger state.
examples/localnet-poc/ submits a transaction and reads it back on LocalNet.
examples/localnet-poc/ submits a transaction and reads it back on DevNet.
Milestone 2: canton-codegen-cpp, canton::admin and Packaging
- Estimated delivery: Month 3. Hard deadline: 4 months from grant approval.
- Estimated effort: ~70 person-days, including the generation and testing of
serialization code for each generated C++ type.
- Focus: Typed end-to-end development from a
.dar.
- Deliverables:
canton-codegen-cpp with its project-owned JVM adapter to
daml-lf-archive: all serializable Daml types, templates, choices, interfaces,
contract keys, transitive dependency closure, and input in both Daml-LF major
versions (LF1 and LF2).
- Daml-LF to C++ type mapping per 2.5, including
canton::Numeric and ordered
map semantics, with generated round-trip tests.
- JSON codecs on generated types and hand-written clients for JSON-only endpoints,
JSON Ledger API create/exercise submission and ACS queries.
- Packaging channels live: CMake
FetchContent/find_package, Conan recipe on a
public remote, vcpkg overlay port, dpm codegen component installable.
- Clean-runner acceptance scripts under
acceptance/packaging/ for CMake, Conan,
vcpkg and dpm.
canton::admin (party/user management and topology reads through the
generated v30 TopologyManagerReadService client).
- Executable examples under
examples/ledger/ and examples/admin/, plus the
examples/codegen/ walkthrough.
- Reusable fixtures and the generated-binding test example described in 2.13.
- Acceptance checks:
- Generate C++ from a
.dar covering all serializable Daml types, interfaces,
contract keys and dependencies; round-trip the generated values through gRPC
and JSON codecs, submit create/exercise commands on both transports, and observe
the transaction.
- Query the ACS through both gRPC and JSON.
- Subscribe over gRPC with party/template/interface filters and decode interface
views into generated types.
- Query topology state through
TopologyManagerReadService.
Run the query through each execution interface in 2.3.
- Regenerate compatible code after a package version bump.
- Link v3 and v4 generated bindings from the same Daml package in one binary.
Repeat with user-selected namespaces and verify that colliding mappings are
rejected during code generation.
- Run the generated-binding test example against scripted ACS and update-stream
fixtures and against LocalNet on a Tier 1 target.
- Verify documented latency histograms and call and error counters, with generated
template and choice metadata, for a successful call and a scripted failure.
Verify structured JSON/gRPC error details, trace-ID injection/extraction and
request/response logging with credentials redacted.
- Read v3 contracts through v4 bindings, with a newly added optional field decoded
as
std::nullopt.
- Read downgrade-compatible v4 data through v3 bindings.
- Execute commands with v3 selected after v4 is uploaded and vetted, then execute
with v4 after an explicit switch of the generated choice API and package
preference.
acceptance/packaging/cmake.sh installs the CMake package on a clean runner and
builds its example project.
acceptance/packaging/conan.sh installs from the published Conan remote on a
clean runner and builds its example project.
acceptance/packaging/vcpkg.sh installs the overlay port on a clean runner and
builds its example project.
acceptance/packaging/dpm.sh installs the dpm component on a clean runner and
generates C++ from the sample .dar.
Milestone 3: canton::token, canton::pqs, canton-conformance-cpp and Security Review
- Estimated delivery: Month 4. Hard deadline: 6 months from grant
approval (the external audit window sits inside this milestone).
- Estimated effort: ~60 person-days plus the external review window.
- Focus: Complete and verify the institutional feature set.
- Deliverables:
canton::token: CIP-0056 transfers and allocation-based settlement; CIP-0112 V2
accounts, revised allocations and holding-change events; Splice transfer
pre-approvals; disclosed-contract and choice-context handling.
- Interactive submission prepare/execute with
canton::Signer, a software signer
and the out-of-process reference signer under examples/external-signing/.
canton::pqs typed read-side client.
canton-conformance-cpp green on the Tier 1 production matrix, with release
results in conformance/results/ and capability definitions and vectors kept
as the SDK's acceptance gate (2.15).
canton-bench-cpp published with its environment, methodology, submission
round-trip p50/p95/p99 and update-stream throughput in benchmarks/results/.
benchmarks/reproduce.sh runs five trials on the recorded runner and reports the
median for each metric.
- Independent security review completed; critical and high findings remediated
and
security/remediation.md published.
- Canton C++ documentation live as described in 2.16: guides, API reference,
examples,
COMPATIBILITY.md, versioning, docs/support.md and
docs/upgrade-playbook.md.
- Token verification environments: Equilibrium will source or deploy the test
setup where the target network permits it:
- V1: a CIP-0056-compliant token on DevNet, with test parties and a balance under
our control.
- V2: a CIP-0112-compliant implementation on DevNet, such as the reference
TestTokenV2 or Canton Coin's V2 implementation when available, with test
parties and assets under our control. Both implementations are described in
CIP-0112.
If a V2 implementation is unavailable on the target DevNet at Milestone 3,
the V2 conformance test runs against the CIP-0112 reference implementation on
LocalNet. We will add the DevNet run when a suitable deployment is available;
that external deployment does not move the milestone deadline.
- Acceptance checks:
- A CIP-0056 transfer settles end to end on DevNet, including a one-step transfer
to a pre-approved receiver.
- A CIP-0112 allocation-based transfer executes on DevNet, or against the
reference implementation on LocalNet under the V2 fallback above.
- An externally signed submission executes through the out-of-process reference
signer.
canton-conformance-cpp publishes green results for the Tier 1 production matrix.
- On the recorded environment, the reproduced submission p50 is within 10 percent
of the published baseline.
- On the recorded environment, the reproduced submission p95 is within 10 percent
of the published baseline.
- On the recorded environment, the reproduced submission p99 is within 15 percent
of the published baseline.
- On the recorded environment, the reproduced update-stream throughput is within
10 percent of the published baseline.
- The independent reviewer delivers the final report.
- Every critical finding is remediated.
- Every high finding is remediated.
security/remediation.md is published.
- The versioned Canton C++ documentation site is live.
docs/support.md is published.
docs/upgrade-playbook.md is published.
Milestone 4: Production Adoption
Milestones 1–3 deliver the core SDK. Milestone 4 supports external teams integrating
it into real applications and taking them to MainNet. Where an integration exposes
a missing reusable capability, Equilibrium can add it to the SDK and help the
adopter put it into use. An application can qualify using the core SDK without
requiring an extension.
Extensions are selected with adopters based on the integration need, estimated
effort and available milestone funding. Each selected extension is released in the
shared SDK with tests and documentation. Deferred Ledger Client Standard features
in 2.15 can be candidates; these milestones do not commit to completing every
remaining Standard row. Fixes to capabilities already committed in Milestones 1–3
remain part of the existing delivery and support obligations.
- Opens: on Milestone 3 acceptance. Deadline: 14 months from grant approval.
- Focus: Verified production usage on Canton MainNet and the adoption outcomes in
the table below. Partial adoption earns partial payment.
- Prerequisites: Within two months of Milestone 3 acceptance and before the
first Milestone 4 payment,
canton-reference-cpp
is published as an open-source service built entirely on the SDK. It submits a
token settlement, follows the resulting update and queries the resulting
PostgreSQL read model through PQS on DevNet or MainNet. The versioned documentation
site, docs/support.md and docs/upgrade-playbook.md remain live and current
through Milestones 4–5. These are delivery requirements, not adoption metrics.
- Payment structure: The MainNet application pool is 500,000 CC, paid as
100,000 CC per qualified application for up to five applications. The completion
tranche is 260,000 CC. It is payable only after at least one production application
qualifies and both completion criteria below are met.
| Deliverable | Acceptance criteria | Tranche payout |
|---|
| Production application on MainNet | Each independent application meets one of the production-use criteria below during one declared 30-day window. Evidence names the organisation, application, SDK version, observation window and relevant party IDs, supported by an on-chain query for submitted transactions or dated activity records for read-only applications, plus adopter confirmation, publicly or by private attestation to the Foundation under an agreed confidentiality arrangement. | 100,000 CC per app, up to five apps |
| Organisation adoption | 3 distinct external organisations each provide a public integration reference or private attestation naming the SDK version and the integration activity performed. | condition of completion tranche |
| Adopter-requested extensions | Every reusable extension requested by an M4 adopter and selected under the rules above is released in the shared SDK with tests and documentation, and the requesting adopter confirms its use in an actual integration or production application. Evidence links the request, SDK release, tests and documentation. If no extension was selected, the qualified adopters confirm that the core SDK covered their workflows. The same extension may serve several adopters. | condition of completion tranche |
| Milestone 4 maximum | | 760,000 CC |
-
Extension record: Selected and declined requests are recorded with reasons.
The completion claim identifies the selected extensions it covers; changes to
that list, including withdrawals, require Foundation agreement.
-
Production-use criteria: Each application qualifies through one of these paths:
- Transaction submission: At least 100 successful SDK-submitted MainNet
transactions during the 30-day window.
- Read-only applications: The application uses the SDK to process MainNet
updates, retrieve or maintain ACS state, or query a PQS database containing
MainNet data for an operational workflow throughout the 30-day window. By
default, the application processes at least 1,000 MainNet updates or issues at
least 100 ACS or PQS queries through the SDK during the window. The Foundation
may agree a different measure and cadence for a specific application before the
window begins. Evidence includes dated processing or query
records, the SDK version and adopter confirmation of how the results are used.
An idle subscription or a one-off demonstration does not qualify. The same
activity criteria apply to that application's subsequent M5 qualification
windows.
Counts use distinct ledger updates, excluding replays, and successful logical
SDK queries, excluding returned rows, individual page fetches and retries.
Historical backfill alone does not establish ongoing production use.
-
Deadline rationale: the month-14 deadline provides about ten months for
adoption after the engineering estimate and eight months after the hard deadline.
This sits between the approved Rust SDK's adoption window and the longer window
used by the C#/.NET SDK. If Milestone 3 is delayed for reasons outside our control,
we will request an extension through the standard renegotiation clause.
-
Verification: adopting teams provide the evidence named in the table directly
to the committee. A production tranche is not payable from a party ID or isolated
transaction alone. Applications must belong to external adopters and perform a
real production workflow; test traffic and the reference application do not count.
Separate deployments or party IDs for the same application do not count as
independent applications. Activity records and adopter confirmation must connect
the claimed activity to the application and SDK version. Adopters confirming
extension use may also count toward the three-organisation integration target.
Observation windows must end by month 14; evidence is submitted within 30 days
after the window closes. An otherwise M4-eligible application remains in M4 if
its evidence is submitted within this period.
Milestone 5: Retention and Expansion
Milestone 5 supports continued production use. Equilibrium works with adopters on
reliability, performance, operational tooling, compatibility and missing edge cases.
Reusable improvements are released in the SDK under the selection rules in
Milestone 4. An adopter can qualify for retention without needing an upgrade or a
new capability.
- Opens: only after Milestone 3 acceptance and either the first Milestone 4
production application qualifies or the M4 deadline is reached.
Deadline: 20 months from grant approval.
- Focus: Sustained MainNet use, successful upgrades, additional production
workflows and new production applications.
- Maintenance: Equilibrium maintains SDK compatibility and security for the
supported releases under
docs/support.md until both M4 and M5 have closed:
compatibility releases for each Canton release on the supported line, security
fixes and COMPATIBILITY.md updates. This work is funded through the Milestone 5
outcomes; no separate maintenance fee is requested.
Each milestone closes when all its targets are accepted or its deadline is
reached: month 14 for M4 and month 20 for M5. Early M5 completion does not end
maintenance while M4 remains open. Any extension requires separate agreement.
- Payment structure: Each of the four metrics below receives 355,500 CC of
the 1,422,000 CC milestone. Each qualifying application or adopter earns an equal
share of its metric's pool, up to that metric's target. The four pools pay
independently; full Milestone 4 completion is not required for any M5 payment.
| Metric | Acceptance criteria | Tranche payout |
|---|
| Retained production applications | 3 M4-qualified applications each meet the applicable production-use criterion in a new 30-day window ending 3–6 months after the end of their original qualifying window. The adopter confirms the application remained in production between the two windows. | 118,500 CC per app |
| Successful upgrades | 3 distinct external adopter organisations each move a production-qualified application to a newer Canton release or a newer SDK minor or major release; an SDK patch release alone does not qualify. Evidence records the old and new versions, the tested SDK/Canton pair in COMPATIBILITY.md, and a 30-day window after the upgrade meeting the applicable production-use criterion. | 118,500 CC per organisation |
| Expanded production use | 3 distinct external adopter organisations each put a materially new SDK capability or workflow into production in a production-qualified application. Evidence identifies the previous use, the added capability and its actual use during a new 30-day window in which the application meets the applicable production-use criterion. Enabling a module or changing a version alone does not qualify. | 118,500 CC per organisation |
| Additional production applications | 2 new independent MainNet applications meet the production-use and evidence requirements after the five M4 application slots are filled or the M4 deadline is reached. After that deadline, eligibility does not depend on the final M4 application count. | 177,750 CC per app |
| Milestone 5 maximum | | 1,422,000 CC |
- Application allocation: While M4 is open, qualifying new applications fill
its application pool first. The M5 additional-application pool is used once those
five slots are filled or M4 reaches its deadline. An application is credited to
only one application pool and cannot later be reassigned to the other pool.
- Verification: The M4 evidence and independence rules apply. Retention is limited
to applications credited to the M4 application pool. Initial production
qualification for upgrades and expansion uses the M4 activity criteria, but does
not require an M4 payment or qualification by month 14. The upgrade or added
workflow must follow that initial qualification window, with the subsequent
30-day window demonstrating production use after the change. An application
or organisation may qualify under more than one M5 metric when it meets each
metric's criteria; the same later window may support those distinct outcomes.
Each application counts once within each application metric, and each organisation
once within each organisation metric. All observation windows must end by the
milestone deadline; evidence is submitted within 30 days after the window closes.
- Deadline rationale: Month 20 allows an application qualifying at the M4
deadline to complete its retention window up to six months later. The reference
application and documentation prerequisites continue to apply to M5 payments.
Acceptance Criteria
Each milestone is accepted against the capabilities and acceptance checks stated under that milestone, with the published artifacts providing the evidence.
- Milestones 1 through 3: the named artifacts are published and each check passes
on the environment named in that check.
- Milestone 4: the Foundation receives the evidence listed in the adoption table.
Per-application payments require qualified MainNet use; the completion payment also
requires at least one qualified production application and both completion
criteria. The reference application and documentation prerequisites apply.
- Milestone 5: the Foundation receives the evidence for each claimed retention,
upgrade, expansion or additional-application outcome. Payments are made separately
against the four pools, subject to their targets and the continued prerequisites.
Central registry listings, upstream documentation and inclusion in Digital Asset's
dpm assembly manifest are reported but do not gate payment. Ledger Client Standard
acceptance covers the v1 mapping and explicitly agreed deviations in 2.15.
Funding
Total Funding Request: Up to 3,967,000 CC plus the separate security-review pass-through.
The request has an engineering and
adoption base and a security-review pass-through.
The base assigns 45 percent to engineering and 55 percent to adoption outcomes.
Milestones 1–3 retain their combined 1,785,000 CC allocation;
Milestone 4 retains 760,000 CC. Milestone 5 adds 1,422,000 CC. Engineering is estimated
at about 180 person-