From 4de34a3088913ed6d7705a6d95dfb4d8f058e313 Mon Sep 17 00:00:00 2001 From: Michael Gaare Date: Wed, 22 Apr 2026 15:45:31 -0400 Subject: [PATCH 1/3] Denex Development Toolkit: Add proposal document --- proposals/denex-development-toolkit.md | 435 +++++++++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 proposals/denex-development-toolkit.md diff --git a/proposals/denex-development-toolkit.md b/proposals/denex-development-toolkit.md new file mode 100644 index 00000000..d03318bc --- /dev/null +++ b/proposals/denex-development-toolkit.md @@ -0,0 +1,435 @@ +# Canton Development Fund Proposal + +## Denex Developer Toolkit: Type-Safe SDKs, Code Generation, and Local Development Frameworks for the Canton Network + +--- + +## 1. Executive Summary + +We propose the continued development and open-source release of the **Denex +Developer Toolkit**: an integrated suite of three purpose-built tools that +directly address the Canton Network's most critical developer experience gaps as +identified in the +[2026 Developer Experience and Tooling Survey](https://discuss.daml.com/t/canton-network-developer-experience-and-tooling-survey-analysis-2026/8412): + +1. **adz**: A Daml-to-TypeScript code generator that produces Zod schemas and + typed package descriptors from Daml source, eliminating the need for manual + type definitions or reliance on deprecated codegen tooling. +2. **Denex SDK**: A type-safe, high-level TypeScript SDK for interacting with + Canton ledger APIs, built on OpenAPI-generated clients and augmented with + Zod-driven runtime type safety, delivering the ergonomic, + "batteries-included" developer experience the community has been requesting. +3. **Denex Localnet**: A configurable local Canton network manager that replaces + the current approach of hardcoded, multi-file configuration with a single + declarative configuration file, programmatic API, and CLI for orchestrating, + inspecting, and modifying running local networks. + +These three tools map directly to the survey's top-priority categories: **Typed +Client SDKs & Code Generators**, **Typed SDKs & Language Bindings**, and **Local +Development Frameworks**, with the latter being the single highest-rated +"Critical" need across all respondents. + +**Funding Requested:** 25,000,000 CC **Timeline:** 9 months **Team:** 8 +developers + +--- + +## 2. Problem Statement + +The Canton Network's 2026 Developer Experience Survey paints a clear picture: +**developers are spending more time fighting infrastructure and tooling gaps +than building applications.** Three findings stand out: + +### 2.1 Environment Setup Is the #1 Bottleneck + +41% of respondents cited environment setup and node operations as the task that +took the longest to "get right." Developers are forced to be **infrastructure +engineers before they can be product builders**. The existing Splice LocalNet +and CN Quickstart approaches require navigating 80-120+ configuration files +spread across Docker Compose fragments, environment files, HOCON configs, +Makefiles, Gradle tasks, and Keycloak realm exports, with hardcoded party hints, +port numbers, OAuth client IDs, and user identifiers scattered throughout. + +### 2.2 No Production-Ready Typed SDK Exists + +The survey explicitly called out the need for **Typed SDKs & Language Bindings** +and **Typed Client SDKs & Code Generators**. The current TypeScript landscape is +fragmented: + +- Digital Asset's own `@daml/ledger` package has not been updated for the + current Canton architecture, and DA's documentation no longer recommends it. +- The official TypeScript tutorial directs developers to use raw `openapi-fetch` + with manually constructed commands, providing functionality but untyped at the + Daml payload level. +- The community tools page lists `@c7/ledger` and `@c7/react` as replacements + for `@daml/ledger`, with no explanation of why a replacement is needed and + minimal adoption (1 GitHub star). +- The Splice Wallet Kernel SDK, while comprehensive for wallet provider + integrations, does not provide a clear story for a typical dApp backend's + interaction with its own ledger. + +### 2.3 The Hardhat/Foundry/Anchor Gap + +The survey's highest-urgency rating went to **Local Development Frameworks**, +where developers specifically name-dropped Hardhat, Foundry, and Anchor as the +standard they expect. They want a single tool to handle scaffolding, testing, +local network management, and deployment. Currently, they are "cobbling +together" scripts. + +--- + +## 3. Proposed Solution + +### 3.1 adz: Daml-to-TypeScript Code Generator + +**Category:** Typed Client SDK & Code Generator + +**What it does:** adz parses Daml source files using a custom Tree-sitter +grammar and generates: + +- **Zod schema files** (one per Daml module) for all data types, templates, + interfaces, and choices +- **Package descriptor files** that map the module/template/choice hierarchy to + typed schemas, ready for use with the Denex SDK's `createPackageContext` + +**Key technical features:** + +- **Source-level parsing** via embedded Tree-sitter WASM, without requiring to + run `daml compile` for codegen (DARs are used only for cross-package + dependency resolution) +- **Single-file distribution** as a self-contained Deno bundle with grammar + embedded +- **Comprehensive Daml construct support:** records, variants, enums, templates + with choices (consuming and non-consuming), interfaces with views, + cross-module imports +- **Precise type mapping:** Daml primitives -> `Daml.*` Zod helpers; `Optional` + -> `Daml.Optional`; `ContractId T` -> `Daml.ContractIdOf("Module.Template")`; + `Map`/`Set` -> appropriate containers; recursive types -> `z.lazy`; tuples -> + structured objects +- **Transitive dependency resolution** across multi-package Daml projects via + DAR inspection +- **Graceful degradation** for unsupported or exotic types (`z.any()` with + comments), where generation never fails silently + +**Impact:** Eliminates the manual process of extracting package IDs from `.dar` +files and hand-coding TypeScript types that the survey identified as a multi-day +friction point. Provides the codegen story that developers from EVM ecosystems +(71% of respondents) expect as table stakes. + +### 3.2 Denex SDK: Type-Safe Canton Ledger API Bindings + +**Category:** Typed SDKs & Language Bindings + +**What it does:** A TypeScript monorepo providing high-level, type-safe access +to Canton ledger, scan, validator, and token standard APIs. Built on +`openapi-fetch` and `openapi-typescript` for the low-level REST layer, augmented +with Zod schemas for runtime type safety at the Daml payload level. + +**Key technical features:** + +- **High-level `Ledger` API** with `submit`, `query`, `queryInterface`, + `queryContractId`, and pagination primitives, providing a curated, ergonomic + surface rather than raw HTTP path construction +- **Command builder pattern** with type-safe `create`, `exercise`, `archive` + operations that validate payloads against Zod schemas at compile time and + runtime +- **Fluent contract wrappers:** `Counter.create({ owner, count, tag })` -> typed + contract instance with `.increment()`, `.decrement()`, `.archive()` methods + and `.asCommand()` for batching +- **Automatic choice name normalization:** Daml's `Offer_Accept` convention -> + `.accept()` method with original name preserved for ledger submission +- **Explicit `Ledger` vs `ClientLedger` split** enforcing disclosure access + rules at the type level so that server-side code gets `$disclosure()`, while + client-side code does not +- **Built-in pagination utilities:** `paginate`, `filter`, `collect`, `reduce` + as async iterables +- **Canton token standard support:** Amulet, Splice, transfer registry, + allocation, and token metadata queries built into the Ledger interface +- **Full auth stack:** OIDC discovery + client credentials with token caching + (`authlib`), browser OAuth via `better-auth` (`web-connector`), session cookie + support for UI apps +- **React integration:** `web-connector-react` with `DenexProvider`, + `useDenexContext`, typed error handling +- **NPM-publishable:** Deno-first development with `dnt` build pipeline for NPM + distribution +- **CIP-0056 compliant** with a roadmap to CIP-0103 compliance + +**Impact:** Replaces the current workflow of manually constructing JSON commands +against untyped `unknown` payloads with a fully typed, IntelliSense-driven +development experience. The fluent API for contract interaction +(`counter.increment({ amount: 2n })`) mirrors the ergonomics of ethers.js and +Anchor that 71% of respondents are accustomed to. + +### 3.3 Denex Localnet: Configurable Local Canton Network Manager + +**Category:** Local Development Framework + +**What it does:** A tool to run, configure, and control Canton local networks +for development and testing, with a single-file declarative configuration model +and both CLI and programmatic APIs. + +**Key technical features:** + +- **Single-file configuration** for the entire localnet topology: number of + participants/validators, party and user onboarding, authentication mode, and + network ports, all existing in one file with straightforward syntax +- **Programmatic API** for configuring and modifying local networks from + application code and test suites +- **CLI tool** for managing running localnets: start, stop, modify topology, + onboard parties, inspect state +- **Runtime state inspection:** Query a running localnet for active users, + ports, parties, and configuration, enabling programmatic integration without + hardcoding parameters +- **Dynamic modification:** Add/remove participants, onboard users and parties + to a running network without restart +- **Test integration:** `test-utils` package with `setupSandbox` for automated + integration testing with party allocation and ledger lifecycle management + +**Impact:** Directly addresses the #1 survey finding. Transforms the current +experience of navigating 80-120+ files across Splice LocalNet and CN Quickstart +into a single, readable configuration. Developers can bring up a customized +Canton network in minutes rather than hours, and integrate it programmatically +into their test suites and CI/CD pipelines. + +--- + +## 4. Comparison with Existing Solutions + +A fair evaluation of this proposal requires addressing the existing tooling +landscape. We believe the Denex Developer Toolkit is complementary to existing +solutions while filling specific, critical gaps they do not address. + +### 4.1 Denex SDK vs. Splice Wallet Kernel SDK + +The [Splice Wallet Kernel](https://github.com/nickkatsios/splice-wallet-kernel) +is a comprehensive monorepo targeting **wallet provider integrations** via the +CIP-0103 dApp API standard. We recognize its value and do not propose to replace +it. Rather, the Denex SDK addresses a different, and currently unserved, +developer persona: **the dApp backend developer who needs to interact with their +own participant node's ledger.** + +| Dimension | Splice Wallet Kernel | Denex SDK | +| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Primary audience** | Wallet providers, exchanges, dApp frontends connecting to wallets | dApp backends, frontends and full-stack developers, automation builders | +| **Core abstraction** | CIP-0103 JSON-RPC protocol between dApps and wallets; `DappClient` proxies ledger calls through wallet gateway | Direct ledger interaction via `Ledger` API with typed commands, queries, and contract wrappers | +| **Type safety at Daml layer** | OpenAPI-generated types for HTTP paths and JSON-RPC schemas; **Daml payload types are `unknown`** unless manually typed via `Ops.*` generics | Zod schemas (hand-written or adz-generated) provide **compile-time and runtime type validation** for all contract payloads, choice arguments, and results | +| **Contract interaction model** | `createArguments` as untyped objects with string `templateId`; developers must manually construct command JSON matching Daml schemas | Fluent wrappers: `Counter.create({ owner, count })`, `counter.increment({ amount: 2n })`, `counter.archive()`, all type-checked | +| **Codegen integration** | OpenAPI + OpenRPC + protobuf codegen for transport layer; **no Daml source -> TypeScript codegen** | Designed for adz integration: package descriptors feed directly into `createPackageContext` for end-to-end type safety from Daml source to TypeScript | +| **API surface** | Two parallel SDK APIs (`WalletSDKImpl` + v1 `Sdk` namespaces) with overlapping but different patterns | Single `Ledger`/`ClientLedger` interface with consistent patterns across server and client | +| **Disclosure model** | Handled within wallet gateway; not exposed as typed API | Explicit `$disclosure()` on `Ledger` (server) with type-level exclusion on `ClientLedger` (browser) | +| **CIP compliance** | CIP-0103 (dApp <-> wallet) | CIP-0056 today, CIP-0103 on roadmap | + +**Why both should exist:** The Splice Wallet Kernel solves the **wallet +connectivity** problem, "how do dApps discover and communicate with user +wallets?" The Denex SDK solves the **ledger interaction** problem, "how does +backend code create, query, and exercise contracts with type safety and +ergonomic APIs?" These are complementary layers in a full-stack Canton +application. A dApp will typically use the Denex SDK on its backend to interact +with its own participant node, and may additionally use the Splice dApp SDK on +its frontend to connect to user wallets via CIP-0103. + +**On the current TypeScript codegen landscape:** Digital Asset's +JavaScript/TypeScript codegen (`daml2js`) depends on the `@daml/ledger` package, +which has not been updated to support the current Canton architecture. DA's own +documentation no longer recommends this path; the +[current TypeScript tutorial](https://docs.digitalasset.com/build/3.5/tutorials/json-api/canton_and_the_json_ledger_api_ts.html) +instead directs developers to use `openapi-fetch` with `openapi-typescript`, +generating types from the JSON Ledger API's OpenAPI specification. While this +provides typed HTTP paths, Daml contract payloads remain `unknown` in the +OpenAPI schema, which is the fundamental gap that adz + Denex SDK closes. + +DA's +[community tools page](https://docs.digitalasset.com/build/3.4/overview/community_tools.html) +lists `@c7/ledger` and `@c7/react` as "replacements for `@daml/ledger` and +`@daml/react`" without elaboration on why replacements are needed or how they +differ. The `@c7/ledger` repository has minimal community adoption (1 GitHub +star, 0 forks) and describes itself as a "TypeScript wrapper around Canton V2 +JSON API", acting as a thin wrapper without the high-level abstractions, codegen +integration, or type-safe contract interaction model that the survey respondents +are requesting. + +**Our commitment to standards:** The Denex SDK is already CIP-0056 compliant. As +part of this grant, we will implement CIP-0103 compliance, ensuring that Denex +SDK applications can participate in the standard dApp <-> wallet protocol while +retaining the ergonomic, type-safe ledger interaction layer that distinguishes +our approach. + +### 4.2 Denex Localnet vs. CN Quickstart / Splice LocalNet + +The [Canton Network Quickstart](https://github.com/digital-asset/cn-quickstart) +(CN Quickstart) is an excellent reference architecture that demonstrates a full +Canton application stack (Spring Boot backend, React frontend, Daml contracts) +running on Splice LocalNet. We do not propose to replace it as a reference +application. Rather, the Denex Localnet addresses the **underlying +infrastructure management problem** that makes CN Quickstart difficult to +customize and integrate into automated workflows. + +| Dimension | CN Quickstart / Splice LocalNet | Denex Localnet | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| **Configuration model** | **80–120+ files** across Docker Compose fragments, `.env` files (37+), HOCON configs (27+), Makefiles, Gradle tasks, Keycloak realm exports, nginx configs, and shell scripts | **Single declarative configuration file** with straightforward syntax for topology, parties, users, auth, and ports | +| **Topology customization** | Fixed 3-role topology (SV, App Provider, App User); adding or removing participants requires editing multiple compose files, env files, HOCON configs, and potentially Keycloak realm data | Configurable number of participants/validators with parties and users specified declaratively | +| **Port management** | Hardcoded port conventions (`4xxx` = SV, `3xxx` = App Provider, `2xxx` = App User) spread across compose files, env, and nginx configs | Ports configurable in one place; introspectable at runtime | +| **Party/user identity** | `PARTY_HINT` env var with strict format validation; full party IDs resolved at runtime via `splice-onboarding` writing to shared Docker volumes; user IDs hardcoded in Keycloak realm exports and env files | Parties and users declared in config; resolvable at runtime via API or CLI without hardcoding | +| **Authentication** | Two modes (`oauth2`/`shared-secret`) selected via `AUTH_MODE`; OAuth requires Keycloak with pre-configured realms, client IDs, and secrets across multiple env files | Auth mode configurable in the single config file | +| **Runtime inspection** | No programmatic way to query active topology, parties, ports, or users; developers must read env files, Docker volume mounts, or navigate web UIs manually | **CLI and programmatic API** to inspect running network state, such as query active parties, ports, users, and configuration | +| **Runtime modification** | Requires stopping the network, editing config files, and restarting | **Modify a running network**: onboard parties/users, adjust topology via API or CLI | +| **Integration testing** | No built-in test harness; developers must manually ensure the network is running and hardcode connection parameters | `test-utils` with `setupSandbox` for automated lifecycle management, party allocation, and teardown | +| **Prerequisites** | Docker >= 27, Compose >= 2.27, direnv, Java 21, Node.js, >= 8 GB RAM; Gradle/Make orchestration | Streamlined prerequisite chain | + +**Why the difference matters:** Consider a developer who wants to test a +multi-party workflow with 4 participants. With CN Quickstart, they would need +to: + +1. Understand the Makefile -> Compose file merge chain +2. Create new compose service definitions for additional participants +3. Add corresponding HOCON configuration files for Canton and Splice +4. Create new env files for each participant's auth configuration +5. Update nginx routing for any new web UIs +6. Potentially modify Keycloak realm exports for new OAuth clients +7. Hardcode the new party IDs and ports into their application code + +With Denex Localnet, they would: + +1. Add entries to their single configuration file +2. Query the running network for the resolved party IDs and ports + +This is the **Hardhat/Foundry/Anchor** experience the survey respondents are asking for. + +--- + +## 5. Development Roadmap + +### Phase 1: Open-Source Release + +| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | +| ---------------------- | ----------------------- | -------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 1.1; Approval + 3 months | adz initial release | adz | 1,000,000 | Daml source code parser and TypeScript code generator producing Zod schemas and typed package descriptors from Daml projects | +| 1.2; Approval + 3 months | SDK initial release | Denex SDK | 500,000 | Collection of Typescript packages providing high-level, type-safe access to Canton ledger, scan, validator using Zod schemas for runtime type safety at the Daml payload level. Publish `@denex/*` packages to public npm registry. | +| 1.3; Approval + 3 months | Token standard fluent API | Denex SDK | 500,000 | Higher-level fluent wrappers for CIP-0056 token standard operations (transfer, allocation, settlement) built on top of the existing schema and query layer | +| 1.4; Approval + 3 months | Localnet initial release | Denex Localnet | 1,000,000 | Command line utility to manage local Canton network | + +**Phase 1 Funding Requested: 3,000,000 CC** + +### Phase 2: Ecosystem Integration + +| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | +| ---------------------- | ----------------------- | -------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 2.1; Approval + 6 months | adz distribution | adz | 1,000,000 | Self-contained single file distribution | +| 2.2; Approval + 6 months | localnet distribution | Denex Localnet | 1,000,000 | Self-contained single file distribution for cli tool | +| 2.3; Approval + 6 months | Documentation | All | 1,000,000 | Unified documentation site; additional examples covering common patterns (DeFi workflows, tokenization, multi-party coordination); + +**Phase 2 Funding Requested: 3,000,000 CC** + +### Phase 3: Hardening + +| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | +| ---------------------- | ----------------------- | -------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 3.1; Approval + 9 months | adz hardening releases | adz | 1,000,000 | Broaden test coverage, improve diagnostic output for unresolved types | +| 3.2; Approval + 9 months | SDK hardening releases | Denex SDK | 1,000,000 | Harden SDK APIs based on real-world usage; improve error handling and edge case coverage across ledger query, command submission, and pagination paths; expand integration test suite | +| 3.3; Approval + 9 months | Localnet hardening releases | Denex Localnet | 1,000,000 | Harden configuration validation, lifecycle management, and runtime state inspection; improve error reporting and expand integration test coverage | + +**Phase 3 Funding Requested: 3,000,000 CC** + +--- + +## 6. Funding & Resources + +**Total Canton Coins requested**: 25,000,000 CC + +| Phase / Commitment; Deadline | Amount (CC) | Trigger | +|----------------------------------------------------|-------------|---------------------------------------| +| Phase 1; Approval + 3 months | 3,000,000 | Committee acceptance of deliverables | +| Phase 2; Approval + 6 months | 3,000,000 | Committee acceptance of deliverables | +| Phase 3; Approval + 9 months | 3,000,000 | Committee acceptance of deliverables | +| Acceleration of Phases 1-3; Approval + 6 months | 1,000,000 | Committee acceptance of deliverables | +| Adoption of Developer Toolkit | 15,000,000 | 1,000,000 CC per instance of repo used by a production-scale or representative Canton deployment; maximum of 15,000,000 CC or 15 instances | + +## Adoption Requirements + +This milestone focuses on validating the tools with real-world Canton app development and ensuring its usability across diverse applications. Denex will: +- Collaborate with the Canton Foundation and ecosystem to onboard 15 member companies or representative Canton deployments +- Support these teams in running the tool on their codebases +- Collect feedback and refine the tool’s output and usability +- Attestation of participation or usage of the tool +- Evidence of successful runs across participating projects + +### Team Composition (8 developers) + +| Role | Count | Focus | +| ------------------------------- | ----- | ------------------------------------------------------------------- | +| Senior TypeScript/SDK Engineers | 3 | Denex SDK core, CIP-0103 implementation, React integration | +| Compiler/Tooling Engineers | 2 | adz code generator, Tree-sitter grammar, IDE integration | +| Infrastructure/DevOps Engineers | 2 | Denex Localnet, Docker orchestration, CI/CD | +| Technical Writer / DX Engineer | 1 | Documentation, tutorials, sample applications, developer onboarding | + +### Resource requirements + +Engineering team (8 developers) Infrastructure & tooling (CI/CD, hosting, +testing) Documentation, design & community feedback Contingency & open-source +maintenance buffer + +## Volatility Stipulation + +This grant is denominated in fixed Canton Coin. Should the project timeline extend beyond 6 months, the remaining un-minted milestones will be renegotiated to account for any significant USD/CC price volatility. + +--- + +## 7. Timeline & Scope Risk Management + +Denex explicitly assumes the financial risk of executing engineering phases (Phases 1-3) parallel to incorporating community feedback. +Should the community discussion change the scope presented in the above Phases, Denex absorbs the wasted work of working against an in-flux specification without requesting supplemental Foundation funds. +Only if major scope is added to the proposal as part of the community discussion will the delivery milestone rewards be revisited. + +--- + +## 8. Team Qualifications + +The Denex team has been building on the Canton Network since its early days, +with deep experience across the Daml/Canton stack: + +- **Active builders:** We are the developers behind the Denex platform, the + creator of the Denex Gas Station and provider of Canton application hosting + infrastructure. Our tools are born from solving real problems in production. +- **Ecosystem contributors:** We have first-hand experience with the developer + pain points identified in the survey; our tools were built because we + encountered these gaps ourselves. +- **TypeScript and tooling expertise:** Our team includes engineers with + backgrounds in compiler tooling (Tree-sitter, code generation), TypeScript SDK + design (OpenAPI, Zod, tRPC), and infrastructure automation (Docker, + Kubernetes). +- **Existing, working code:** Unlike a speculative proposal, we are presenting + **functional, tested tools** with integration test suites running against + Canton sandboxes. This grant funds maturation and open-source release, not + greenfield R&D. + +--- + +## 9. Open-Source Commitment + +All tools developed under this grant will be released under the **Apache 2.0** +license: + +- **adz:** https://github.com/denex-io/adz +- **Denex SDK:** https://github.com/denex-io/denex-sdk +- **Denex Localnet:** https://github.com/denex-io/denex-localnet + +--- + +## 10. Alignment with Canton Network Priorities + +This proposal directly addresses the Canton Network's stated priorities from the +2026 Developer Experience and Tooling Survey: + +| Survey Priority | Denex Toolkit Component | Alignment | +| ---------------------------------------------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------- | +| **Local Development Frameworks** (rated "Critical" or highest urgency) | Denex Localnet | Single-file config, CLI, programmatic API (the "Hardhat for Canton") | +| **Typed SDKs & Language Bindings** | Denex SDK | Type-safe ledger API with fluent contract wrappers and Zod validation | +| **Typed Client SDK & Code Generator** | adz | Daml -> TypeScript + Zod codegen, eliminating manual type extraction | +| **Conceptual Paradigm Shift** (EVM -> Canton learning curve) | Denex SDK | Familiar ethers.js-like ergonomics (`.create()`, `.increment()`, `.archive()`) | +| **Integration Friction** (Package ID discovery, frontend integration) | adz + Denex SDK | Automatic package ID embedding in generated descriptors; web-connector for browser dApps | +| **Standardized Wallet Adapter** | Denex SDK (CIP-0103 roadmap) | Standards-compliant wallet interaction alongside ergonomic direct ledger access | + +--- + +_Submitted by the Denex Team for consideration by the Canton Development Fund +Grants Committee._ From 33a8a464c6820d8ee5cc3ec530b2d09acf77d9c8 Mon Sep 17 00:00:00 2001 From: Michael Gaare Date: Thu, 23 Apr 2026 17:31:07 -0400 Subject: [PATCH 2/3] Clarify denex-localnet requirements --- proposals/denex-development-toolkit.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/proposals/denex-development-toolkit.md b/proposals/denex-development-toolkit.md index d03318bc..aa6754e2 100644 --- a/proposals/denex-development-toolkit.md +++ b/proposals/denex-development-toolkit.md @@ -265,7 +265,7 @@ infrastructure management problem** that makes CN Quickstart difficult to customize and integrate into automated workflows. | Dimension | CN Quickstart / Splice LocalNet | Denex Localnet | -| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------| | **Configuration model** | **80–120+ files** across Docker Compose fragments, `.env` files (37+), HOCON configs (27+), Makefiles, Gradle tasks, Keycloak realm exports, nginx configs, and shell scripts | **Single declarative configuration file** with straightforward syntax for topology, parties, users, auth, and ports | | **Topology customization** | Fixed 3-role topology (SV, App Provider, App User); adding or removing participants requires editing multiple compose files, env files, HOCON configs, and potentially Keycloak realm data | Configurable number of participants/validators with parties and users specified declaratively | | **Port management** | Hardcoded port conventions (`4xxx` = SV, `3xxx` = App Provider, `2xxx` = App User) spread across compose files, env, and nginx configs | Ports configurable in one place; introspectable at runtime | @@ -274,7 +274,8 @@ customize and integrate into automated workflows. | **Runtime inspection** | No programmatic way to query active topology, parties, ports, or users; developers must read env files, Docker volume mounts, or navigate web UIs manually | **CLI and programmatic API** to inspect running network state, such as query active parties, ports, users, and configuration | | **Runtime modification** | Requires stopping the network, editing config files, and restarting | **Modify a running network**: onboard parties/users, adjust topology via API or CLI | | **Integration testing** | No built-in test harness; developers must manually ensure the network is running and hardcode connection parameters | `test-utils` with `setupSandbox` for automated lifecycle management, party allocation, and teardown | -| **Prerequisites** | Docker >= 27, Compose >= 2.27, direnv, Java 21, Node.js, >= 8 GB RAM; Gradle/Make orchestration | Streamlined prerequisite chain | +| **Prerequisites** | Docker >= 27, Compose >= 2.27, direnv, Java 21, Node.js, >= 8 GB RAM; Gradle/Make orchestration | Docker, Deno/Node.Js, memory requirements vary on requested network size | + **Why the difference matters:** Consider a developer who wants to test a multi-party workflow with 4 participants. With CN Quickstart, they would need From 5cb7b00ff4054bb4be6573d8d701546b4075057f Mon Sep 17 00:00:00 2001 From: Michael Gaare Date: Thu, 7 May 2026 15:34:31 -0400 Subject: [PATCH 3/3] denex toolkit revisions: split out localnet, clarifications on sdk --- proposals/denex-development-toolkit.md | 737 ++++++++++++++----------- 1 file changed, 424 insertions(+), 313 deletions(-) diff --git a/proposals/denex-development-toolkit.md b/proposals/denex-development-toolkit.md index aa6754e2..15b64918 100644 --- a/proposals/denex-development-toolkit.md +++ b/proposals/denex-development-toolkit.md @@ -1,80 +1,74 @@ # Canton Development Fund Proposal -## Denex Developer Toolkit: Type-Safe SDKs, Code Generation, and Local Development Frameworks for the Canton Network +## Denex Developer SDK: Type-Safe SDK and Code Generation for the Canton Network --- ## 1. Executive Summary We propose the continued development and open-source release of the **Denex -Developer Toolkit**: an integrated suite of three purpose-built tools that -directly address the Canton Network's most critical developer experience gaps as -identified in the +Developer SDK**, a TypeScript toolchain for building Canton applications. It +addresses the two highest-priority TypeScript gaps identified in the [2026 Developer Experience and Tooling Survey](https://discuss.daml.com/t/canton-network-developer-experience-and-tooling-survey-analysis-2026/8412): - -1. **adz**: A Daml-to-TypeScript code generator that produces Zod schemas and - typed package descriptors from Daml source, eliminating the need for manual - type definitions or reliance on deprecated codegen tooling. -2. **Denex SDK**: A type-safe, high-level TypeScript SDK for interacting with - Canton ledger APIs, built on OpenAPI-generated clients and augmented with - Zod-driven runtime type safety, delivering the ergonomic, - "batteries-included" developer experience the community has been requesting. -3. **Denex Localnet**: A configurable local Canton network manager that replaces - the current approach of hardcoded, multi-file configuration with a single - declarative configuration file, programmatic API, and CLI for orchestrating, - inspecting, and modifying running local networks. - -These three tools map directly to the survey's top-priority categories: **Typed -Client SDKs & Code Generators**, **Typed SDKs & Language Bindings**, and **Local -Development Frameworks**, with the latter being the single highest-rated -"Critical" need across all respondents. - -**Funding Requested:** 25,000,000 CC **Timeline:** 9 months **Team:** 8 +**Typed Client SDKs & Code Generators** and **Typed SDKs & Language Bindings**. + +The toolchain is organized as three independently usable pieces: + +1. **A strongly typed `Ledger` interface** defining a high-level, ergonomic API + to interact with Canton. +2. **Pluggable transport implementations** of that interface. A direct + server-side implementation against the JSON Ledger API v2, the Scan Proxy + API, and Token Standard registries; a tRPC-based client transport for browser + and automation use that exposes the same shape over a thin RPC. Additional + transports can be plugged in without changing application code. +3. **Typed contract interaction tooling** driven by Zod schemas: a command + builder, fluent contract wrappers, paginated-query pipelines, and a + disclosure-aware exercise model. The schemas can be hand-written for + third-party packages or generated by the code generator _**adz**_ from Daml + source. + +These pieces can be used independently — a developer who already has a preferred +transport can use just the schemas and command builder; a developer who already +has hand-written types can use just the typed `Ledger` and its transports — and +integrate cleanly when used together. + +**Funding Requested:** 17,000,000 CC **Timeline:** 9 months **Team:** 6 developers --- ## 2. Problem Statement -The Canton Network's 2026 Developer Experience Survey paints a clear picture: -**developers are spending more time fighting infrastructure and tooling gaps -than building applications.** Three findings stand out: - -### 2.1 Environment Setup Is the #1 Bottleneck - -41% of respondents cited environment setup and node operations as the task that -took the longest to "get right." Developers are forced to be **infrastructure -engineers before they can be product builders**. The existing Splice LocalNet -and CN Quickstart approaches require navigating 80-120+ configuration files -spread across Docker Compose fragments, environment files, HOCON configs, -Makefiles, Gradle tasks, and Keycloak realm exports, with hardcoded party hints, -port numbers, OAuth client IDs, and user identifiers scattered throughout. - -### 2.2 No Production-Ready Typed SDK Exists - -The survey explicitly called out the need for **Typed SDKs & Language Bindings** -and **Typed Client SDKs & Code Generators**. The current TypeScript landscape is -fragmented: - -- Digital Asset's own `@daml/ledger` package has not been updated for the - current Canton architecture, and DA's documentation no longer recommends it. -- The official TypeScript tutorial directs developers to use raw `openapi-fetch` - with manually constructed commands, providing functionality but untyped at the - Daml payload level. -- The community tools page lists `@c7/ledger` and `@c7/react` as replacements - for `@daml/ledger`, with no explanation of why a replacement is needed and - minimal adoption (1 GitHub star). -- The Splice Wallet Kernel SDK, while comprehensive for wallet provider - integrations, does not provide a clear story for a typical dApp backend's - interaction with its own ledger. - -### 2.3 The Hardhat/Foundry/Anchor Gap - -The survey's highest-urgency rating went to **Local Development Frameworks**, -where developers specifically name-dropped Hardhat, Foundry, and Anchor as the -standard they expect. They want a single tool to handle scaffolding, testing, -local network management, and deployment. Currently, they are "cobbling -together" scripts. +The 2026 Developer Experience and Tooling Survey identifies typed SDKs and +codegen among the high-impact tooling needs across the Canton developer +community. The report's "magic wand" wishlist names **Typed SDKs & Language +Bindings**; the "additional developer tooling opportunities" section names +**Typed Client SDK & Code Generator** as a distinct category. The survey also +notes that **71% of respondents come from an Ethereum (EVM) background**, with +explicit name-drops of Web3.js, MetaMask, Hardhat, Foundry, and Anchor as the +ergonomic baselines those developers expect. + +For TypeScript developers building on current Canton, significant pieces of the +stack between "OpenAPI-generated HTTP client" and "application code" are +typically assembled per project: + +- The JSON Ledger API's OpenAPI specification types Daml contract payloads, + choice arguments, and choice results as `unknown` — the spec cannot describe + them, because they are Daml-defined, not Canton-defined. Decoding, validation, + and command assembly happen at every call site. +- Multi-call workflows — token-standard factory resolution, ACS pagination + across an offset-stable snapshot, choice-context lookups, disclosure handling + — are not covered by transport-layer codegen and are typically re-implemented + per project. +- Fluent contract-interaction ergonomics familiar from EVM ecosystems + (`counter.increment({ amount: 2n })`, `.archive()`, paginated `.query()` + pipelines) are not provided by transport-layer codegen and are not defined as + a pattern any single library currently delivers across both server and browser + environments. + +The Denex SDK aims to fill these gaps by consolidating typing, command building, +and contract-interaction ergonomics into a single layer above existing +transports. --- @@ -84,217 +78,332 @@ together" scripts. **Category:** Typed Client SDK & Code Generator -**What it does:** adz parses Daml source files using a custom Tree-sitter -grammar and generates: +adz reads Daml source and emits, for each Daml package: -- **Zod schema files** (one per Daml module) for all data types, templates, - interfaces, and choices -- **Package descriptor files** that map the module/template/choice hierarchy to - typed schemas, ready for use with the Denex SDK's `createPackageContext` +- **Zod schemas** for all data types, templates, interfaces, and choices, with + inferred TypeScript types ready to use directly in application code. +- **A package descriptor** that ties those schemas to the package's module, + template, and choice hierarchy and feeds directly into the SDK's typed package + context (see §3.2). -**Key technical features:** +**Key features:** -- **Source-level parsing** via embedded Tree-sitter WASM, without requiring to - run `daml compile` for codegen (DARs are used only for cross-package - dependency resolution) -- **Single-file distribution** as a self-contained Deno bundle with grammar - embedded - **Comprehensive Daml construct support:** records, variants, enums, templates - with choices (consuming and non-consuming), interfaces with views, - cross-module imports -- **Precise type mapping:** Daml primitives -> `Daml.*` Zod helpers; `Optional` - -> `Daml.Optional`; `ContractId T` -> `Daml.ContractIdOf("Module.Template")`; - `Map`/`Set` -> appropriate containers; recursive types -> `z.lazy`; tuples -> - structured objects -- **Transitive dependency resolution** across multi-package Daml projects via - DAR inspection -- **Graceful degradation** for unsupported or exotic types (`z.any()` with - comments), where generation never fails silently - -**Impact:** Eliminates the manual process of extracting package IDs from `.dar` -files and hand-coding TypeScript types that the survey identified as a multi-day -friction point. Provides the codegen story that developers from EVM ecosystems -(71% of respondents) expect as table stakes. - -### 3.2 Denex SDK: Type-Safe Canton Ledger API Bindings + with consuming and non-consuming choices, interfaces with views, cross-module + imports. +- **Application-shaped TypeScript types.** Daml scalars decode into the + TypeScript types developers actually use: `Int → bigint`, + `Numeric → + Decimal` (with no precision loss), `Time → Date`, `Party` and + `ContractId` as branded strings with format checks. +- **Comment carry-over.** Daml documentation comments on records, fields, + templates, and choices are propagated to the generated TypeScript as TSDoc + comments, so editor tooltips, IntelliSense, and generated docs see the same + prose the Daml author wrote. +- **Cross-package dependency resolution** for projects that depend on + third-party Daml packages. +- **Faithful Daml-LF JSON encoding.** The generated schemas target the + documented + [Daml-LF JSON encoding](https://docs.digitalasset.com/build/3.4/reference/json-api/lf-value-specification.html) + on both sides of the transform. An `Int` arrives as a string on the wire and + is decoded into a `bigint` for application code; a `Numeric` arrives as a + string and is decoded into a `Decimal` without precision loss; on submission, + both are re-encoded to the strings the ledger expects. `Variant` round-trips + as `{ tag, value }`, `Optional` as `null` or value, records as JSON objects — + all per the LF spec. +- **Graceful degradation.** Types that cannot be represented exactly are emitted + with permissive schemas and explanatory comments rather than causing + generation to fail silently. + +#### What the generated code looks like + +For a small Daml template: + +```haskell +module Counter where + + +-- | A simple owned counter. +template Counter + with + owner : Party -- ^ Party owning the counter. + count: Int -- ^ Current value. + tag: Text -- ^ Free-form label for grouping. + where + signatory owner + + -- | Increase the count by `amount`. + choice Increment : ContractId Counter + with + amount : Int -- ^ Can be negative! + controller owner + do create this with count = this.count + amount + + -- | Decrease the count by `amount`. + choice Decrement : ContractId Counter + with + amount : Int + controller owner + do create this with count = this.count - amount + + -- | Read the current count without modifying the contract. + nonconsuming choice Read : Int + controller owner + do return this.count +``` + +adz emits Zod schemas with the Daml comments propagated as TSDoc: + +```typescript +// AUTO-GENERATED from DAML source. Do not edit by hand. + +import { z } from "zod"; + +import * as Daml from "@denex/sdk-api/daml"; + +/** A simple owned counter. */ +export const Counter = z.object({ + /** Party owning the counter. */ + owner: Daml.Party, + /** Current value. */ + count: Daml.Int, + /** Free-form label for grouping. */ + tag: Daml.Text, +}); +export type Counter = z.infer; + +/** Increase the count by `amount`. */ +export const Increment_ChoiceArg = z.object({ + /** Can be negative! */ + amount: Daml.Int, +}); +export type Increment_ChoiceArg = z.infer; +export const Increment_ChoiceResult = Daml.ContractIdOf("Counter.Counter"); +export type Increment_ChoiceResult = z.infer; +/** Decrease the count by `amount`. */ +export const Decrement_ChoiceArg = z.object({ + amount: Daml.Int, +}); +export type Decrement_ChoiceArg = z.infer; +export const Decrement_ChoiceResult = Daml.ContractIdOf("Counter.Counter"); +export type Decrement_ChoiceResult = z.infer; +/** Read the current count without modifying the contract. */ +export const Read_ChoiceArg = z.object({}); +export type Read_ChoiceArg = z.infer; +export const Read_ChoiceResult = Daml.Int; +export type Read_ChoiceResult = z.infer; +``` + +…and a package descriptor that ties them together for the SDK: + +```typescript +// AUTO-GENERATED from DAML source. Do not edit by hand. + +import * as CounterZod from "./Counter.zod.ts"; + +export default { + packageId: "#counter" as const, + modules: { + Counter: { + templates: { + Counter: { + payload: CounterZod.Counter, + choices: { + Increment: { + argument: CounterZod.Increment_ChoiceArg, + result: CounterZod.Increment_ChoiceResult, + consuming: true, + }, + Decrement: { + argument: CounterZod.Decrement_ChoiceArg, + result: CounterZod.Decrement_ChoiceResult, + consuming: true, + }, + Read: { + argument: CounterZod.Read_ChoiceArg, + result: CounterZod.Read_ChoiceResult, + consuming: false, + }, + }, + }, + }, + }, + }, +} as const; +``` + +The Zod schemas are independently usable — a developer who only wants +runtime-validated payload types can import them directly into application code. +The package descriptor is what unlocks the higher-level command builder and +contract wrappers in the SDK. + +### 3.2 Denex SDK: Layered, Typed Canton Ledger Access **Category:** Typed SDKs & Language Bindings -**What it does:** A TypeScript monorepo providing high-level, type-safe access -to Canton ledger, scan, validator, and token standard APIs. Built on -`openapi-fetch` and `openapi-typescript` for the low-level REST layer, augmented -with Zod schemas for runtime type safety at the Daml payload level. - -**Key technical features:** - -- **High-level `Ledger` API** with `submit`, `query`, `queryInterface`, - `queryContractId`, and pagination primitives, providing a curated, ergonomic - surface rather than raw HTTP path construction -- **Command builder pattern** with type-safe `create`, `exercise`, `archive` - operations that validate payloads against Zod schemas at compile time and - runtime -- **Fluent contract wrappers:** `Counter.create({ owner, count, tag })` -> typed - contract instance with `.increment()`, `.decrement()`, `.archive()` methods - and `.asCommand()` for batching -- **Automatic choice name normalization:** Daml's `Offer_Accept` convention -> - `.accept()` method with original name preserved for ledger submission -- **Explicit `Ledger` vs `ClientLedger` split** enforcing disclosure access - rules at the type level so that server-side code gets `$disclosure()`, while - client-side code does not -- **Built-in pagination utilities:** `paginate`, `filter`, `collect`, `reduce` - as async iterables -- **Canton token standard support:** Amulet, Splice, transfer registry, - allocation, and token metadata queries built into the Ledger interface -- **Full auth stack:** OIDC discovery + client credentials with token caching - (`authlib`), browser OAuth via `better-auth` (`web-connector`), session cookie - support for UI apps -- **React integration:** `web-connector-react` with `DenexProvider`, - `useDenexContext`, typed error handling -- **NPM-publishable:** Deno-first development with `dnt` build pipeline for NPM - distribution -- **CIP-0056 compliant** with a roadmap to CIP-0103 compliance - -**Impact:** Replaces the current workflow of manually constructing JSON commands -against untyped `unknown` payloads with a fully typed, IntelliSense-driven -development experience. The fluent API for contract interaction -(`counter.increment({ amount: 2n })`) mirrors the ergonomics of ethers.js and -Anchor that 71% of respondents are accustomed to. - -### 3.3 Denex Localnet: Configurable Local Canton Network Manager - -**Category:** Local Development Framework - -**What it does:** A tool to run, configure, and control Canton local networks -for development and testing, with a single-file declarative configuration model -and both CLI and programmatic APIs. - -**Key technical features:** - -- **Single-file configuration** for the entire localnet topology: number of - participants/validators, party and user onboarding, authentication mode, and - network ports, all existing in one file with straightforward syntax -- **Programmatic API** for configuring and modifying local networks from - application code and test suites -- **CLI tool** for managing running localnets: start, stop, modify topology, - onboard parties, inspect state -- **Runtime state inspection:** Query a running localnet for active users, - ports, parties, and configuration, enabling programmatic integration without - hardcoding parameters -- **Dynamic modification:** Add/remove participants, onboard users and parties - to a running network without restart -- **Test integration:** `test-utils` package with `setupSandbox` for automated - integration testing with party allocation and ledger lifecycle management - -**Impact:** Directly addresses the #1 survey finding. Transforms the current -experience of navigating 80-120+ files across Splice LocalNet and CN Quickstart -into a single, readable configuration. Developers can bring up a customized -Canton network in minutes rather than hours, and integrate it programmatically -into their test suites and CI/CD pipelines. +The Denex SDK is a TypeScript monorepo organized as three layers, each +independently usable. + +#### 3.2.1 The typed `Ledger` interface + +A higher-level facade over a curated subset of Canton's REST APIs, exposing the +operations a typical Canton application needs: identity and ledger state, +command submission, contract and interface queries with paginated results, and +the multi-call workflows for the Canton token standard (factory resolution, +choice contexts, disclosed contracts, instrument metadata). All inputs and +outputs are typed end-to-end against Zod schemas, so payloads, choice arguments, +and choice results are validated at the boundary rather than left as `unknown`. + +A parallel client-side variant of the interface is intended for less trusted +environments such as a web browser. Its surface is the same shape as the +server-side interface, minus the operations that are inappropriate in those +environments (e.g. disclosure access). The distinction is enforced at the +TypeScript type level so that client code cannot accidentally call into +server-only functionality. + +#### 3.2.2 Pluggable transport implementations + +Two transports are delivered under this grant: + +- **Direct server-side**: implements `Ledger` against the JSON Ledger API v2, + the Scan Proxy API, and the Token Standard registry, transfer-instruction, and + allocation-instruction APIs. Uses OpenAPI-generated clients for the HTTP + layer; we do not reimplement transport. +- **tRPC-based client transport**: implements `ClientLedger` over + [tRPC](https://trpc.io/), with a thin proxy router that wraps a server-side + `Ledger` and exposes it to browser or Node clients. Application code on either + side of the wire imports the same schemas, command types, and contract + wrappers; the wire format is defined by the same Zod schemas the rest of the + SDK uses. + +The interface is transport-agnostic by design. Additional transports can be +added without changes to application code, schemas, command builder, or contract +wrappers. + +#### 3.2.3 Typed contract interaction + +Given a package descriptor (hand-written or adz-generated) and a `Ledger` +instance, the SDK builds a typed package context with fluent template and +contract wrappers: + +```typescript +import { createPackageContext } from "@denex/sdk-api"; +import { paginate } from "@denex/sdk-api/pagination"; +import CounterPackage from "./generated/counter"; // adz-generated + +// One-time setup: bind a ledger, package descriptor, and acting party. +const pkg = createPackageContext(ledger, CounterPackage, userParty); + +// Template wrapper: typed factory for Counter contracts. +const Counter = pkg.Template("Counter.Counter"); + +// Create a contract — payload type-checked and runtime-validated. +let counter = await Counter.create({ + owner: pkg.actAs, + count: 3n, // bigint, not string + tag: "demo", +}); + +// Exercise a consuming choice — argument type-checked, result wrapped +// automatically into a new Counter contract wrapper. +counter = await counter.increment({ amount: 2n }); + +// Find active Counter contracts visible to userParty, paginated and filtered. +const matching = await paginate(Counter.query) + .filter((c) => c.payload.tag === "demo") + .collect(); + +// Archive +await counter.archive(); +``` + +For multi-command transactions, every method has a corresponding `.asCommand()` +factory that produces a `Command` carrying its own argument and result schemas: + +```typescript +const [created, incremented] = await ledger.submit(userParty, [ + Counter.create.asCommand({ owner: userParty, count: 0n, tag: "x" }), + Counter(existingCid).increment.asCommand({ amount: 1n }), +]); +// Each tuple element is typed precisely to its command's result. +``` + +The `submit` return type is computed from the input commands: each tuple +position carries the result type of the corresponding command, with no manual +casts. + +#### 3.2.4 Pagination over query results + +The JSON Ledger API exposes contract queries as a single request returning a +single result set, capped by a configured per-call result-size limit on the +participant; exceeding the limit produces a `413 Content Too Large` rather than +continuing the read. The OpenAPI spec describes no pagination construct on top +of that. + +The Denex SDK presents query results as a paginated, fluent pipeline that scales +beyond the per-call limit: + +```typescript +import { paginate } from "@denex/sdk-api/pagination"; + +const matching = await paginate(Counter.query) + .filter((c) => c.payload.tag === "demo") + .collect(); +``` + +Pages are consumed lazily, and a `paginate(...)` pipeline can be filtered, +mapped, reduced, or used directly with `for await` without exposing offsets, +page tokens, or snapshot mechanics to application code. + +#### 3.2.5 Token standard and Splice support + +The SDK builds on the Daml interfaces and registry REST APIs defined in +[CIP-0056](https://github.com/canton-foundation/cips/blob/main/cip-0056/cip-0056.md), +covering the workflows a token-standard dApp actually has to perform: resolving +transfer and allocation factories with their choice contexts and disclosures, +exercising instruction-level choices on transfer and allocation instructions, +and listing instrument metadata. Splice-specific surfaces — Canton Coin's +`AmuletRules`, `OpenMiningRound`, and featured- app rights — are also wired in +for dApps building on Splice directly. + +- **A high-level API for factory and disclosure resolution.** Exercising a + transfer or allocation choice under CIP-0056 requires resolving the factory + contract, fetching its choice context, and collecting the disclosed contracts + the factory needs before assembling the `submit` call. The SDK provides typed + helpers that perform that resolution and return a bundle in the shape `submit` + consumes; the dApp passes the bundle into `submit` directly, without + constructing registry request bodies, unpacking response envelopes, or + threading choice-context payloads and disclosed-contract arrays by hand. +- **Splice and token-standard data types are described as Zod schemas.** Factory + arguments, choice contexts, instrument metadata, transfer and allocation + instruction shapes, and Splice-specific contracts like `AmuletRules` and + `OpenMiningRound` — registry and scan-proxy responses arrive as fully typed, + decoded TypeScript values rather than the `unknown` payloads the CIP-0056 + OpenAPI specs necessarily leave for the client to handle. --- -## 4. Comparison with Existing Solutions - -A fair evaluation of this proposal requires addressing the existing tooling -landscape. We believe the Denex Developer Toolkit is complementary to existing -solutions while filling specific, critical gaps they do not address. - -### 4.1 Denex SDK vs. Splice Wallet Kernel SDK - -The [Splice Wallet Kernel](https://github.com/nickkatsios/splice-wallet-kernel) -is a comprehensive monorepo targeting **wallet provider integrations** via the -CIP-0103 dApp API standard. We recognize its value and do not propose to replace -it. Rather, the Denex SDK addresses a different, and currently unserved, -developer persona: **the dApp backend developer who needs to interact with their -own participant node's ledger.** - -| Dimension | Splice Wallet Kernel | Denex SDK | -| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Primary audience** | Wallet providers, exchanges, dApp frontends connecting to wallets | dApp backends, frontends and full-stack developers, automation builders | -| **Core abstraction** | CIP-0103 JSON-RPC protocol between dApps and wallets; `DappClient` proxies ledger calls through wallet gateway | Direct ledger interaction via `Ledger` API with typed commands, queries, and contract wrappers | -| **Type safety at Daml layer** | OpenAPI-generated types for HTTP paths and JSON-RPC schemas; **Daml payload types are `unknown`** unless manually typed via `Ops.*` generics | Zod schemas (hand-written or adz-generated) provide **compile-time and runtime type validation** for all contract payloads, choice arguments, and results | -| **Contract interaction model** | `createArguments` as untyped objects with string `templateId`; developers must manually construct command JSON matching Daml schemas | Fluent wrappers: `Counter.create({ owner, count })`, `counter.increment({ amount: 2n })`, `counter.archive()`, all type-checked | -| **Codegen integration** | OpenAPI + OpenRPC + protobuf codegen for transport layer; **no Daml source -> TypeScript codegen** | Designed for adz integration: package descriptors feed directly into `createPackageContext` for end-to-end type safety from Daml source to TypeScript | -| **API surface** | Two parallel SDK APIs (`WalletSDKImpl` + v1 `Sdk` namespaces) with overlapping but different patterns | Single `Ledger`/`ClientLedger` interface with consistent patterns across server and client | -| **Disclosure model** | Handled within wallet gateway; not exposed as typed API | Explicit `$disclosure()` on `Ledger` (server) with type-level exclusion on `ClientLedger` (browser) | -| **CIP compliance** | CIP-0103 (dApp <-> wallet) | CIP-0056 today, CIP-0103 on roadmap | - -**Why both should exist:** The Splice Wallet Kernel solves the **wallet -connectivity** problem, "how do dApps discover and communicate with user -wallets?" The Denex SDK solves the **ledger interaction** problem, "how does -backend code create, query, and exercise contracts with type safety and -ergonomic APIs?" These are complementary layers in a full-stack Canton -application. A dApp will typically use the Denex SDK on its backend to interact -with its own participant node, and may additionally use the Splice dApp SDK on -its frontend to connect to user wallets via CIP-0103. - -**On the current TypeScript codegen landscape:** Digital Asset's -JavaScript/TypeScript codegen (`daml2js`) depends on the `@daml/ledger` package, -which has not been updated to support the current Canton architecture. DA's own -documentation no longer recommends this path; the -[current TypeScript tutorial](https://docs.digitalasset.com/build/3.5/tutorials/json-api/canton_and_the_json_ledger_api_ts.html) -instead directs developers to use `openapi-fetch` with `openapi-typescript`, -generating types from the JSON Ledger API's OpenAPI specification. While this -provides typed HTTP paths, Daml contract payloads remain `unknown` in the -OpenAPI schema, which is the fundamental gap that adz + Denex SDK closes. - -DA's -[community tools page](https://docs.digitalasset.com/build/3.4/overview/community_tools.html) -lists `@c7/ledger` and `@c7/react` as "replacements for `@daml/ledger` and -`@daml/react`" without elaboration on why replacements are needed or how they -differ. The `@c7/ledger` repository has minimal community adoption (1 GitHub -star, 0 forks) and describes itself as a "TypeScript wrapper around Canton V2 -JSON API", acting as a thin wrapper without the high-level abstractions, codegen -integration, or type-safe contract interaction model that the survey respondents -are requesting. - -**Our commitment to standards:** The Denex SDK is already CIP-0056 compliant. As -part of this grant, we will implement CIP-0103 compliance, ensuring that Denex -SDK applications can participate in the standard dApp <-> wallet protocol while -retaining the ergonomic, type-safe ledger interaction layer that distinguishes -our approach. - -### 4.2 Denex Localnet vs. CN Quickstart / Splice LocalNet - -The [Canton Network Quickstart](https://github.com/digital-asset/cn-quickstart) -(CN Quickstart) is an excellent reference architecture that demonstrates a full -Canton application stack (Spring Boot backend, React frontend, Daml contracts) -running on Splice LocalNet. We do not propose to replace it as a reference -application. Rather, the Denex Localnet addresses the **underlying -infrastructure management problem** that makes CN Quickstart difficult to -customize and integrate into automated workflows. - -| Dimension | CN Quickstart / Splice LocalNet | Denex Localnet | -|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------| -| **Configuration model** | **80–120+ files** across Docker Compose fragments, `.env` files (37+), HOCON configs (27+), Makefiles, Gradle tasks, Keycloak realm exports, nginx configs, and shell scripts | **Single declarative configuration file** with straightforward syntax for topology, parties, users, auth, and ports | -| **Topology customization** | Fixed 3-role topology (SV, App Provider, App User); adding or removing participants requires editing multiple compose files, env files, HOCON configs, and potentially Keycloak realm data | Configurable number of participants/validators with parties and users specified declaratively | -| **Port management** | Hardcoded port conventions (`4xxx` = SV, `3xxx` = App Provider, `2xxx` = App User) spread across compose files, env, and nginx configs | Ports configurable in one place; introspectable at runtime | -| **Party/user identity** | `PARTY_HINT` env var with strict format validation; full party IDs resolved at runtime via `splice-onboarding` writing to shared Docker volumes; user IDs hardcoded in Keycloak realm exports and env files | Parties and users declared in config; resolvable at runtime via API or CLI without hardcoding | -| **Authentication** | Two modes (`oauth2`/`shared-secret`) selected via `AUTH_MODE`; OAuth requires Keycloak with pre-configured realms, client IDs, and secrets across multiple env files | Auth mode configurable in the single config file | -| **Runtime inspection** | No programmatic way to query active topology, parties, ports, or users; developers must read env files, Docker volume mounts, or navigate web UIs manually | **CLI and programmatic API** to inspect running network state, such as query active parties, ports, users, and configuration | -| **Runtime modification** | Requires stopping the network, editing config files, and restarting | **Modify a running network**: onboard parties/users, adjust topology via API or CLI | -| **Integration testing** | No built-in test harness; developers must manually ensure the network is running and hardcode connection parameters | `test-utils` with `setupSandbox` for automated lifecycle management, party allocation, and teardown | -| **Prerequisites** | Docker >= 27, Compose >= 2.27, direnv, Java 21, Node.js, >= 8 GB RAM; Gradle/Make orchestration | Docker, Deno/Node.Js, memory requirements vary on requested network size | - - -**Why the difference matters:** Consider a developer who wants to test a -multi-party workflow with 4 participants. With CN Quickstart, they would need -to: - -1. Understand the Makefile -> Compose file merge chain -2. Create new compose service definitions for additional participants -3. Add corresponding HOCON configuration files for Canton and Splice -4. Create new env files for each participant's auth configuration -5. Update nginx routing for any new web UIs -6. Potentially modify Keycloak realm exports for new OAuth clients -7. Hardcode the new party IDs and ports into their application code - -With Denex Localnet, they would: - -1. Add entries to their single configuration file -2. Query the running network for the resolved party IDs and ports - -This is the **Hardhat/Foundry/Anchor** experience the survey respondents are asking for. +## 4. Relationship to Existing Tooling + +The Denex SDK builds on top of OpenAPI-generated clients, providing a +higher-level, ergonomic API that elevates build-time and runtime type safety +with Zod schemas and orchestrates multi-step workflows. + +`dpm codegen-js` produces TypeScript type definitions paired with decoders and +encoders built on +[`@mojotech/json-type-validation`](https://github.com/mojotech/json-type-validation), +and a per-template runtime registry. Wrapper libraries that mediate between the +JSON Ledger API and application code consume this runtime surface to validate +contract payloads, serialize command arguments, and round-trip choice results. +`adz` produces a different output set — Zod schemas, per-package descriptor +modules, and TSDoc preserved from Daml docstrings — that the Denex SDK consumes +for the same purposes, with application-shaped scalar values (`bigint` for +`Int`, `Decimal` for `Numeric`, `Date` for `Time`, branded `ContractId` and +`Party`) decoded at the boundary rather than threaded through call sites as +branded strings. The Zod schemas are independently usable: a project that +prefers to work directly against an OpenAPI-generated client can plug them into +its own request and response handling to recover the same boundary validation +and application-shaped values, without taking on the rest of the SDK. --- @@ -302,84 +411,89 @@ This is the **Hardhat/Foundry/Anchor** experience the survey respondents are ask ### Phase 1: Open-Source Release -| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | -| ---------------------- | ----------------------- | -------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| 1.1; Approval + 3 months | adz initial release | adz | 1,000,000 | Daml source code parser and TypeScript code generator producing Zod schemas and typed package descriptors from Daml projects | -| 1.2; Approval + 3 months | SDK initial release | Denex SDK | 500,000 | Collection of Typescript packages providing high-level, type-safe access to Canton ledger, scan, validator using Zod schemas for runtime type safety at the Daml payload level. Publish `@denex/*` packages to public npm registry. | -| 1.3; Approval + 3 months | Token standard fluent API | Denex SDK | 500,000 | Higher-level fluent wrappers for CIP-0056 token standard operations (transfer, allocation, settlement) built on top of the existing schema and query layer | -| 1.4; Approval + 3 months | Localnet initial release | Denex Localnet | 1,000,000 | Command line utility to manage local Canton network | +| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | +| ------------------------ | ------------------------- | --------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1.1; Approval + 3 months | adz initial release | adz | 1,000,000 | Daml source code parser and TypeScript code generator producing Zod schemas and typed package descriptors from Daml projects | +| 1.2; Approval + 3 months | SDK initial release | Denex SDK | 500,000 | Collection of Typescript packages providing the typed `Ledger` interface, server-side direct transport (JSON Ledger API v2, Scan Proxy, Token Standard), tRPC client transport, command builder, contract wrappers, and pagination. Publish `@denex/*` packages to public npm registry. | +| 1.3; Approval + 3 months | Token standard fluent API | Denex SDK | 500,000 | Higher-level fluent wrappers for CIP-0056 token standard operations (transfer, allocation, settlement) built on top of the existing schema and query layer | -**Phase 1 Funding Requested: 3,000,000 CC** +**Phase 1 Funding Requested: 2,000,000 CC** ### Phase 2: Ecosystem Integration -| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | -| ---------------------- | ----------------------- | -------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| 2.1; Approval + 6 months | adz distribution | adz | 1,000,000 | Self-contained single file distribution | -| 2.2; Approval + 6 months | localnet distribution | Denex Localnet | 1,000,000 | Self-contained single file distribution for cli tool | -| 2.3; Approval + 6 months | Documentation | All | 1,000,000 | Unified documentation site; additional examples covering common patterns (DeFi workflows, tokenization, multi-party coordination); +| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | +| ------------------------ | ---------------- | -------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| 2.1; Approval + 6 months | adz distribution | adz | 1,000,000 | Self-contained single file distribution | +| 2.2; Approval + 6 months | Documentation | All | 1,000,000 | Unified documentation site; additional examples covering common patterns (DeFi workflows, tokenization, multi-party coordination) | -**Phase 2 Funding Requested: 3,000,000 CC** +**Phase 2 Funding Requested: 2,000,000 CC** ### Phase 3: Hardening -| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | -| ---------------------- | ----------------------- | -------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| 3.1; Approval + 9 months | adz hardening releases | adz | 1,000,000 | Broaden test coverage, improve diagnostic output for unresolved types | -| 3.2; Approval + 9 months | SDK hardening releases | Denex SDK | 1,000,000 | Harden SDK APIs based on real-world usage; improve error handling and edge case coverage across ledger query, command submission, and pagination paths; expand integration test suite | -| 3.3; Approval + 9 months | Localnet hardening releases | Denex Localnet | 1,000,000 | Harden configuration validation, lifecycle management, and runtime state inspection; improve error reporting and expand integration test coverage | +| Milestone; Deadline | Deliverable | Category | Requested Funding (CC) | Description | +| ------------------------ | ---------------------- | --------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 3.1; Approval + 9 months | adz hardening releases | adz | 1,000,000 | Broaden test coverage, improve diagnostic output for unresolved types | +| 3.2; Approval + 9 months | SDK hardening releases | Denex SDK | 1,000,000 | Harden SDK APIs based on real-world usage; improve error handling and edge case coverage across ledger query, command submission, and pagination paths; expand integration test suite | -**Phase 3 Funding Requested: 3,000,000 CC** +**Phase 3 Funding Requested: 2,000,000 CC** --- ## 6. Funding & Resources -**Total Canton Coins requested**: 25,000,000 CC +**Total Canton Coins requested**: 17,000,000 CC -| Phase / Commitment; Deadline | Amount (CC) | Trigger | -|----------------------------------------------------|-------------|---------------------------------------| -| Phase 1; Approval + 3 months | 3,000,000 | Committee acceptance of deliverables | -| Phase 2; Approval + 6 months | 3,000,000 | Committee acceptance of deliverables | -| Phase 3; Approval + 9 months | 3,000,000 | Committee acceptance of deliverables | -| Acceleration of Phases 1-3; Approval + 6 months | 1,000,000 | Committee acceptance of deliverables | -| Adoption of Developer Toolkit | 15,000,000 | 1,000,000 CC per instance of repo used by a production-scale or representative Canton deployment; maximum of 15,000,000 CC or 15 instances | +| Phase / Commitment; Deadline | Amount (CC) | Trigger | +| ----------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| Phase 1; Approval + 3 months | 2,000,000 | Committee acceptance of deliverables | +| Phase 2; Approval + 6 months | 2,000,000 | Committee acceptance of deliverables | +| Phase 3; Approval + 9 months | 2,000,000 | Committee acceptance of deliverables | +| Acceleration of Phases 1-3; Approval + 6 months | 1,000,000 | Committee acceptance of deliverables | +| Adoption of Developer SDK and adz | 10,000,000 | 1,000,000 CC per instance of repo used by a production-scale or representative Canton deployment; maximum of 10,000,000 CC or 10 instances | ## Adoption Requirements -This milestone focuses on validating the tools with real-world Canton app development and ensuring its usability across diverse applications. Denex will: -- Collaborate with the Canton Foundation and ecosystem to onboard 15 member companies or representative Canton deployments +This milestone focuses on validating the tools with real-world Canton app +development and ensuring its usability across diverse applications. Denex will: + +- Collaborate with the Canton Foundation and ecosystem to onboard at least 10 + member companies or representative Canton deployments - Support these teams in running the tool on their codebases - Collect feedback and refine the tool’s output and usability - Attestation of participation or usage of the tool - Evidence of successful runs across participating projects -### Team Composition (8 developers) +### Team Composition (6 developers) | Role | Count | Focus | | ------------------------------- | ----- | ------------------------------------------------------------------- | -| Senior TypeScript/SDK Engineers | 3 | Denex SDK core, CIP-0103 implementation, React integration | -| Compiler/Tooling Engineers | 2 | adz code generator, Tree-sitter grammar, IDE integration | -| Infrastructure/DevOps Engineers | 2 | Denex Localnet, Docker orchestration, CI/CD | +| Senior TypeScript/SDK Engineers | 3 | Denex SDK core | +| Compiler/Tooling Engineers | 2 | adz code generator, parser/grammar tooling | | Technical Writer / DX Engineer | 1 | Documentation, tutorials, sample applications, developer onboarding | ### Resource requirements -Engineering team (8 developers) Infrastructure & tooling (CI/CD, hosting, +Engineering team (6 developers) Infrastructure & tooling (CI/CD, hosting, testing) Documentation, design & community feedback Contingency & open-source maintenance buffer ## Volatility Stipulation -This grant is denominated in fixed Canton Coin. Should the project timeline extend beyond 6 months, the remaining un-minted milestones will be renegotiated to account for any significant USD/CC price volatility. +This grant is denominated in fixed Canton Coin. Should the project timeline +extend beyond 6 months, the remaining un-minted milestones will be renegotiated +to account for any significant USD/CC price volatility. --- ## 7. Timeline & Scope Risk Management -Denex explicitly assumes the financial risk of executing engineering phases (Phases 1-3) parallel to incorporating community feedback. -Should the community discussion change the scope presented in the above Phases, Denex absorbs the wasted work of working against an in-flux specification without requesting supplemental Foundation funds. -Only if major scope is added to the proposal as part of the community discussion will the delivery milestone rewards be revisited. +Denex explicitly assumes the financial risk of executing engineering phases +(Phases 1-3) parallel to incorporating community feedback. Should the community +discussion change the scope presented in the above Phases, Denex absorbs the +wasted work of working against an in-flux specification without requesting +supplemental Foundation funds. Only if major scope is added to the proposal as +part of the community discussion will the delivery milestone rewards be +revisited. --- @@ -395,9 +509,9 @@ with deep experience across the Daml/Canton stack: pain points identified in the survey; our tools were built because we encountered these gaps ourselves. - **TypeScript and tooling expertise:** Our team includes engineers with - backgrounds in compiler tooling (Tree-sitter, code generation), TypeScript SDK - design (OpenAPI, Zod, tRPC), and infrastructure automation (Docker, - Kubernetes). + backgrounds in compiler tooling (parser/grammar tooling, code generation), + TypeScript SDK design (OpenAPI, Zod, tRPC), and infrastructure automation + (Docker, Kubernetes). - **Existing, working code:** Unlike a speculative proposal, we are presenting **functional, tested tools** with integration test suites running against Canton sandboxes. This grant funds maturation and open-source release, not @@ -412,7 +526,6 @@ license: - **adz:** https://github.com/denex-io/adz - **Denex SDK:** https://github.com/denex-io/denex-sdk -- **Denex Localnet:** https://github.com/denex-io/denex-localnet --- @@ -421,14 +534,12 @@ license: This proposal directly addresses the Canton Network's stated priorities from the 2026 Developer Experience and Tooling Survey: -| Survey Priority | Denex Toolkit Component | Alignment | -| ---------------------------------------------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------- | -| **Local Development Frameworks** (rated "Critical" or highest urgency) | Denex Localnet | Single-file config, CLI, programmatic API (the "Hardhat for Canton") | -| **Typed SDKs & Language Bindings** | Denex SDK | Type-safe ledger API with fluent contract wrappers and Zod validation | -| **Typed Client SDK & Code Generator** | adz | Daml -> TypeScript + Zod codegen, eliminating manual type extraction | -| **Conceptual Paradigm Shift** (EVM -> Canton learning curve) | Denex SDK | Familiar ethers.js-like ergonomics (`.create()`, `.increment()`, `.archive()`) | -| **Integration Friction** (Package ID discovery, frontend integration) | adz + Denex SDK | Automatic package ID embedding in generated descriptors; web-connector for browser dApps | -| **Standardized Wallet Adapter** | Denex SDK (CIP-0103 roadmap) | Standards-compliant wallet interaction alongside ergonomic direct ledger access | +| Survey Priority | Denex SDK Component | Alignment | +| --------------------------------------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | +| **Typed SDKs & Language Bindings** | Denex SDK | Typed `Ledger` interface with pluggable transports, fluent contract wrappers, Zod-driven runtime validation | +| **Typed Client SDK & Code Generator** | adz | Daml → Zod schemas + package descriptors, eliminating manual type extraction | +| **Conceptual Paradigm Shift** (EVM → Canton learning curve) | Denex SDK | Familiar ethers.js-like ergonomics (`.create()`, `.increment()`, `.archive()`) | +| **Integration Friction** (Package ID discovery, frontend integration) | adz + Denex SDK | Comprehensive Daml-to-TypeScript mapping, including package ID embedding; tRPC client transport for browser dApps | ---