Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions docs-main/appdev/modules/m4-dapp-sdk.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
title: "dApp SDK"
description: "Connect a Canton Network dApp to user wallets using the dApp SDK, a TypeScript library that implements CIP-103."
---

The dApp SDK (`@canton-network/dapp-sdk`) is a TypeScript library that lets a dApp connect to user wallets on Canton Network. It implements [CIP-103](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md), a vendor-neutral JSON-RPC 2.0 protocol for the dApp API. Any wallet that implements CIP-103 works with any dApp built on the SDK.

For step-by-step API details, see the [dApp SDK integration docs](/integrations/dapp-sdk/overview).

## Where it fits

A Canton Network dApp talks to three external systems: the user's wallet, a Canton validator (for the Ledger API), and a signing provider that holds the user's keys. The dApp SDK covers the wallet side.

```mermaid
flowchart LR
D["Your dApp<br/>(dApp SDK)"]
G[Wallet Gateway]
V[Canton Validator]
S[Signing Provider]
D <-->|dApp API (CIP-103)<br/>HTTP / postMessage| G
G <-->|Ledger API| V
G <-->|Signing| S
```

The dApp uses the SDK to call the dApp API (`connect`, `listAccounts`, `prepareExecute`, `signMessage`, `ledgerApi`, and others). The wallet on the other end is typically a [Wallet Gateway](/appdev/modules/m4-wallet-gateway), which implements the dApp API, manages user sessions, and forwards requests to the validator and signing provider. The SDK abstracts the transport: HTTP for remote gateways, `postMessage` for browser-extension wallets. The same dApp code runs against either.

## Two levels of API

The SDK exposes two interfaces over the same protocol:

- **High-level dApp SDK**: `sdk.connect()`, `sdk.listAccounts()`, `sdk.prepareExecute(...)`. Recommended for most applications.
- **Provider API**: low-level [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193)-style interface using `provider.request({ method, params })`. Useful for direct protocol access or for integrating with existing provider-based code.

The two can be mixed. `sdk.getConnectedProvider()` returns the active CIP-103 provider, so you can drop down to `provider.request(...)` whenever the high-level API doesn't cover what you need.

## Provider discovery (`window.canton`)

Browser-extension wallets are discovered through `window.canton`, an EIP-1193-style provider that the SDK injects. A dApp running in the browser finds the wallet there. The SDK handles registration, EIP-1193 events, and the user-facing wallet picker. See [Adapter registration & wallet discovery](/integrations/dapp-sdk/adapters-and-discovery) for customization.

## Typical flow

A common dApp lifecycle:

1. **Initialize.** Call `sdk.init()` once at app startup. This registers adapters and attempts to restore any previously connected session without opening the picker.

```typescript
import * as sdk from '@canton-network/dapp-sdk'

await sdk.init()
```

2. **Connect.** When the user clicks *Connect Wallet*, call `sdk.connect()`. If multiple wallets are registered, the SDK shows the picker; otherwise it proceeds directly. The wallet may redirect the user to its UI to log in (OAuth or self-signed JWT).

```typescript
const result = await sdk.connect()
if (result.isConnected) {
// session established; dApp API calls now work
}
```

3. **Read accounts.** List the parties (accounts) the wallet has for this user and find the primary one.

```typescript
const accounts = await sdk.listAccounts()
const primary = accounts.find(a => a.primary)
```

4. **Submit a transaction.** `prepareExecute` runs the full prepare → user-approval → sign → submit lifecycle. The wallet shows the user the transaction details and asks for approval; if granted, the signing provider produces the signature and the wallet submits to the validator.

```typescript
await sdk.prepareExecute({
commands: [
{
CreateCommand: {
templateId: '#AdminWorkflows:Canton.Internal.Ping:Ping',
createArguments: {
id: `ping-${Date.now()}`,
initiator: primary.partyId,
responder: primary.partyId,
},
},
},
],
})
```

5. **React to events.** The SDK emits `statusChanged`, `accountsChanged`, and `txChanged` so your UI stays in sync with the wallet. Remove listeners when components unmount.

```typescript
sdk.onTxChanged(tx => {
if (tx.status === 'executed') {
console.log('update id:', tx.payload.updateId)
}
})
```

For the full method surface (including `signMessage`, `ledgerApi` proxying, `getActiveNetwork`, and the event subscription API), see the [API reference](/integrations/dapp-sdk/api-reference).

## When to drop down to the Provider API

Reach for `provider.request(...)` directly when the method you need isn't yet wrapped by the high-level SDK, when you're integrating with existing CIP-103-aware code that expects EIP-1193 semantics, or when you're writing a wallet provider yourself and want a thin client for testing.

Both interfaces speak the same protocol, so the choice is ergonomic, not functional.

## Where to go next

- [Installation](/integrations/dapp-sdk/download): install the SDK from npm.
- [Usage guide](/integrations/dapp-sdk/usage): every method shown side-by-side in SDK and Provider API form.
- [Best practices](/integrations/dapp-sdk/best-practices): recommended patterns for production dApps.
- [Wallet Gateway module](/appdev/modules/m4-wallet-gateway): the server side of the dApp API.
- [Examples](/integrations/dapp-building-examples): Ping and Portfolio sample dApps.
96 changes: 96 additions & 0 deletions docs-main/appdev/modules/m4-wallet-gateway.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: "Wallet Gateway"
description: "The server that mediates between Canton Network dApps, validator nodes, and signing providers, and how to think about it when building a dApp."
---

The Wallet Gateway is a JavaScript/TypeScript server that sits between a dApp and the Canton Network. It implements the dApp API (the CIP-103 JSON-RPC protocol the [dApp SDK](/appdev/modules/m4-dapp-sdk) speaks) and translates the calls into Ledger API requests against a Canton validator and signing requests to a configured signing provider.

For setup, configuration, and operational details, see the [Wallet Gateway integration docs](/integrations/wallet-gateway/overview).

## Why a mediator exists

Canton's privacy model means a validator node only sees the subset of ledger state relevant to its parties. There is no single global state shared across all nodes. A dApp can't just "talk to the chain"; it has to find a validator that hosts the user's party, and the validator has to accept commands signed by the right key.

The Wallet Gateway centralizes that responsibility. To the dApp, the Gateway looks like a wallet: a single JSON-RPC endpoint that knows the user's accounts, signs on their behalf via the configured signing provider, and submits transactions to the right validator. To the validator, the Gateway is an authenticated Ledger API client.

## What it provides

The Gateway exposes two JSON-RPC surfaces. The **dApp API** is what dApps call (`connect`, `listAccounts`, `prepareExecute`, `signMessage`, and a `ledgerApi` proxy). The **User API** is for users and automation: session management, identity-provider configuration, wallet creation, network configuration, and direct signing. A web **User UI** built on top of the User API handles the human-facing flows (login, wallet management, transaction approval). Custom integrations can call the User API directly instead.

A Gateway can be configured for multiple Canton networks (DevNet, TestNet, MainNet, or a custom synchronizer); users pick a network when they create a wallet. Signing is delegated to a pluggable backend: a Canton participant, the Gateway itself (test only), Fireblocks, Blockdaemon, or a similar provider. Sessions, wallet metadata, and transaction history live in one of the supported storage backends (in-memory for dev, SQLite, or PostgreSQL).

## Where it fits

```mermaid
flowchart LR
D["Your dApp<br/>(dApp SDK)"]
U[User]
subgraph WG[Wallet Gateway]
direction TB
DA[dApp API]
UA[User API]
UI[User UI]
end
V[Canton Validator]
S["Signing Provider<br/>(Participant, Fireblocks, …)"]
D <-->|CIP-103 over<br/>HTTP / postMessage| DA
U -->|browser| UI
U -->|programmatic| UA
WG <-->|Ledger API| V
WG <-->|Signing| S
```

- **dApp → Gateway**: CIP-103 JSON-RPC over HTTP or `postMessage`.
- **User → Gateway**: User UI (browser) or User API (programmatic).
- **Gateway → Canton**: authenticated requests to a validator's Ledger API.
- **Gateway → Signing Provider**: signing requests to whichever provider the user's wallet is configured for.

## Discovery and connection flow

A typical user-facing flow:

1. **Discovery.** A dApp finds available Wallet Gateways via well-known URLs, a registry, or a browser extension that injects `window.canton`. Each Gateway publishes its base URL and supported networks.
2. **Connect.** The user picks a Gateway. The dApp calls `sdk.connect()`. The Gateway redirects the user to its User UI to log in if they don't have a session yet (OAuth or self-signed JWT).
3. **Session.** After login the Gateway returns a JWT. The dApp SDK uses it to authenticate subsequent dApp API calls.
4. **Transaction.** When the dApp calls `prepareExecute`, the Gateway prepares the transaction with the validator, shows the user the details in the User UI for approval, asks the signing provider to sign, then submits to the validator. The dApp receives the result and `txChanged` events.

## Do you need to run one?

For most dApps the answer is no; users bring their own Wallet Gateway. Typical scenarios:

| Scenario | Who runs the Gateway |
|---|---|
| Public dApp, retail users | Users connect via a browser-extension wallet or a hosted Gateway run by a wallet provider. |
| Enterprise dApp, known users | The dApp operator or a partner runs a Gateway shared by all users. |
| Internal tools and automation | The team runs a Gateway in their own infrastructure, often paired with an internal signing provider. |
| Development | You run a local Gateway alongside the validator, typically with the in-Gateway signing provider for testing. |

If you're building a dApp, you mainly care about the client-facing dApp API. That's what the dApp SDK calls; the Gateway is the production target on the other end of those calls.

If you're operating Canton infrastructure or running a dApp at scale, you'll likely run a Gateway too. The [Getting Started](/integrations/wallet-gateway/download) guide walks through standing one up.

## Signing providers

The Wallet Gateway does not sign transactions itself in production. It delegates to a configured provider.

A **Canton participant** signs in-band: the participant node holds the party's key in its key store, and the Gateway requests signatures over the participant's admin API. This is the default for SV-operated and enterprise deployments. **Internal** signing means the Gateway generates and stores the key itself; that mode is for test and development only. **Fireblocks** and **Blockdaemon** are external providers that hold the key in their own MPC or HSM infrastructure and produce signatures via API.

A single Gateway can host wallets across different signing providers; the provider is configured per wallet. See [Signing Providers](/integrations/wallet-gateway/signing-providers) for configuration.

## What a dApp developer should know

Two operational realities affect how a dApp behaves, even if you'll never operate a Gateway.

The user picks the network at the Gateway level, so your dApp should not assume `da-mainnet`. Call `sdk.getActiveNetwork()` and react to `accountsChanged`.

The signing provider determines transaction latency. A local participant signs in milliseconds; an external HSM-backed provider can take seconds. Don't lock the UI on `prepareExecute`; subscribe to `txChanged` and let the user keep working.

## Where to go next

- [Wallet Gateway overview](/integrations/wallet-gateway/overview): what it is, what it provides, and what's in the integration docs.
- [Getting Started](/integrations/wallet-gateway/download): install and run a Gateway.
- [Configuration](/integrations/wallet-gateway/configuration): full config-file reference.
- [APIs](/integrations/wallet-gateway/apis): dApp API and User API method reference.
- [Signing Providers](/integrations/wallet-gateway/signing-providers): how to wire up each backend.
- [dApp SDK module](/appdev/modules/m4-dapp-sdk): the client side of the dApp API.
- [Examples](/integrations/dapp-building-examples): Ping and Portfolio sample dApps that talk to a Wallet Gateway.
12 changes: 10 additions & 2 deletions docs-main/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@
"appdev/quickstart/running-the-demo",
"appdev/modules/m4-backend-dev",
"appdev/modules/m4-frontend-dev",
"appdev/modules/m4-dapp-sdk",
"appdev/modules/m4-wallet-gateway",
"appdev/modules/m4-json-api-tutorial",
"appdev/modules/m4-canton-coin",
"appdev/modules/m4-featured-app-activity-marker",
Expand Down Expand Up @@ -504,29 +506,35 @@
"pages": [
"integrations/overview",
"integrations/integration-patterns",
"integrations/dapp-building-overview"
"integrations/dapp-building-overview",
"integrations/dapp-building-examples"
]
},
{
"group": "dApp SDK",
"pages": [
"integrations/dapp-sdk/overview",
"integrations/dapp-sdk/download",
{
"group": "dApp SDK Integration Guide",
"pages": [
"integrations/dapp-sdk/usage",
"integrations/dapp-sdk/adapters-and-discovery",
"integrations/dapp-sdk/wallet-provider-integration",
"integrations/dapp-sdk/best-practices"
"integrations/dapp-sdk/best-practices",
"integrations/dapp-sdk/api-reference"
]
}
]
},
{
"group": "Wallet Gateway",
"pages": [
"integrations/wallet-gateway/overview",
"integrations/wallet-gateway/download",
"integrations/wallet-gateway/configuration",
"integrations/wallet-gateway/configuration-schema",
"integrations/wallet-gateway/deployment",
{
"group": "Wallet Gateway Integration Guide",
"pages": [
Expand Down
39 changes: 39 additions & 0 deletions docs-main/integrations/dapp-building-examples.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: "Examples"
description: "Sample dApps (Ping, Portfolio) demonstrating dApp SDK and Wallet Gateway integration."
---

{/* COPIED_START source="wallet-gateway:docs/dapp-building/examples/index.md" hash="6a5aa740" */}

The following example dApps demonstrate how to use the dApp SDK and Wallet Gateway. You can find them in the [`/examples`](https://github.com/canton-network/wallet/tree/main/examples) directory of the repository.

## Ping

A minimal example dApp that imports the dApp SDK and communicates with a Wallet Gateway. Built with React + TypeScript using the Vite template, this is the best starting point for understanding the basics of dApp SDK integration.

**Running:**

```bash
yarn install
yarn dev
```

[Source code](https://github.com/canton-network/wallet/tree/main/examples/ping)

## Portfolio

A more complete example dApp that showcases a minimal but functional portfolio application using the dApp SDK and Wallet Gateway. Built with React + TypeScript using Vite, it demonstrates real-world patterns including holdings, allocations, transactions, and transfer workflows.

**Building and running:**

Because this example has a number of dependencies, it is recommended to use the scripts in the root repository for development:

```bash
yarn build:all
yarn start:all # this service lives at http://localhost:8081
yarn stop:all
```

[Source code](https://github.com/canton-network/wallet/tree/main/examples/portfolio)

{/* COPIED_END */}
30 changes: 19 additions & 11 deletions docs-main/integrations/dapp-building-overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,23 @@ A typical setup involves:

## High-Level Architecture

```
┌─────────────┐ dApp API ┌──────────────────┐ Ledger API ┌─────────────────┐
│ Your dApp │ ◄──────────────────► │ Wallet Gateway │ ◄─────────────────► │ Canton Validator│
│ (dApp SDK) │ (HTTP / WebSocket) │ │ │ │
└─────────────┘ │ ┌────────────┐ │ Signing └─────────────────┘
│ │ │ User API │ │
│ User interactions │ │ User UI │ │ ┌─────────────────┐
└────────────────────────────►│ └────────────┘ │ ◄──►│ Signing Provider│
(User UI / User API) │ │ │ (Participant, │
└──────────────────┘ │ Fireblocks…) │
└─────────────────┘
```mermaid
flowchart LR
D["Your dApp<br/>(dApp SDK)"]
U[User]
subgraph WG[Wallet Gateway]
direction TB
DA[dApp API]
UA[User API]
UI[User UI]
end
V[Canton Validator]
S["Signing Provider<br/>(Participant, Fireblocks, …)"]
D <-->|dApp API<br/>HTTP / WebSocket| DA
U -->|browser| UI
U -->|programmatic| UA
WG <-->|Ledger API| V
WG <-->|Signing| S
```

- **dApp → Wallet Gateway**: Your dApp uses the dApp SDK to call the **dApp API** (connect, list accounts, prepare and execute transactions). The SDK can use HTTP (remote Wallet Gateway) or `postMessage` (browser extension).
Expand Down Expand Up @@ -65,3 +71,5 @@ See [Usage](/integrations/wallet-gateway/usage) and [APIs](/integrations/wallet-
- **Using the User UI or User API?** → See [Usage](/integrations/wallet-gateway/usage) for typical workflows and when to use which interface.

{/* COPIED_END */}

{/* LOCAL_MODIFICATION: the "High-Level Architecture" diagram was converted from ASCII box-drawing to mermaid for consistency with other diagrams in the project. The diagram is the only divergence from the upstream source; the surrounding prose is verbatim. */}
Loading