diff --git a/docs-main/appdev/modules/m4-dapp-sdk.mdx b/docs-main/appdev/modules/m4-dapp-sdk.mdx
new file mode 100644
index 00000000..7591cb32
--- /dev/null
+++ b/docs-main/appdev/modules/m4-dapp-sdk.mdx
@@ -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
(dApp SDK)"]
+ G[Wallet Gateway]
+ V[Canton Validator]
+ S[Signing Provider]
+ D <-->|dApp API (CIP-103)
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.
diff --git a/docs-main/appdev/modules/m4-wallet-gateway.mdx b/docs-main/appdev/modules/m4-wallet-gateway.mdx
new file mode 100644
index 00000000..c6e41176
--- /dev/null
+++ b/docs-main/appdev/modules/m4-wallet-gateway.mdx
@@ -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
(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
(Participant, Fireblocks, …)"]
+ D <-->|CIP-103 over
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.
diff --git a/docs-main/docs.json b/docs-main/docs.json
index 1777fe01..0f3a8432 100644
--- a/docs-main/docs.json
+++ b/docs-main/docs.json
@@ -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",
@@ -504,12 +506,14 @@
"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",
@@ -517,7 +521,8 @@
"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"
]
}
]
@@ -525,8 +530,11 @@
{
"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": [
diff --git a/docs-main/integrations/dapp-building-examples.mdx b/docs-main/integrations/dapp-building-examples.mdx
new file mode 100644
index 00000000..7bf4a71f
--- /dev/null
+++ b/docs-main/integrations/dapp-building-examples.mdx
@@ -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 */}
diff --git a/docs-main/integrations/dapp-building-overview.mdx b/docs-main/integrations/dapp-building-overview.mdx
index 7a93b4b0..3f54a926 100644
--- a/docs-main/integrations/dapp-building-overview.mdx
+++ b/docs-main/integrations/dapp-building-overview.mdx
@@ -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
(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
(Participant, Fireblocks, …)"]
+ D <-->|dApp API
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).
@@ -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. */}
diff --git a/docs-main/integrations/dapp-sdk/api-reference.mdx b/docs-main/integrations/dapp-sdk/api-reference.mdx
new file mode 100644
index 00000000..2cc2f6c6
--- /dev/null
+++ b/docs-main/integrations/dapp-sdk/api-reference.mdx
@@ -0,0 +1,114 @@
+---
+title: "API Reference"
+description: "Method-by-method reference for the dApp SDK and the underlying CIP-103 Provider API."
+---
+
+{/* COPIED_START source="wallet-gateway:docs/dapp-building/dapp-sdk/api-reference.md" hash="48132304" */}
+
+The dApp SDK implements the **dApp API** as defined in [CIP-0103](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md). The API provides a standardized, transport-agnostic interface that enables decentralized applications (dApps) to securely interact with the Canton Network via Wallets.
+
+The dApp API exists in two variants, each targeting a different deployment model and interaction pattern.
+
+## OpenRPC Specifications
+
+The machine-readable API specifications are maintained in the repository:
+
+- **Sync API**: [openrpc-dapp-api.json](https://github.com/canton-network/wallet/blob/main/api-specs/openrpc-dapp-api.json)
+- **Async API**: [openrpc-dapp-remote-api.json](https://github.com/canton-network/wallet/blob/main/api-specs/openrpc-dapp-remote-api.json)
+
+## Synchronous dApp API (Sync API)
+
+The **Synchronous dApp API** is intended for clients that have direct access to a Wallet, such as browser extensions or desktop applications.
+In this model, methods and events are executed in a standard request-response fashion, allowing dApps to perform ledger reads, transaction preparation, and signing operations immediately.
+
+This variant is the canonical choice for end-user applications, providing a familiar synchronous programming model and minimizing latency between user actions and dApp responses.
+
+**Methods:**
+
+| Method | Output | Description |
+| ------------------- | ------------- | --------------------------------------------------------------- |
+| `connect` | ConnectResult | Establishes a connection to the Wallet |
+| `disconnect` | void | Closes the session between the client and the provider |
+| `isConnected` | ConnectResult | Indicates connectivity to the Wallet |
+| `status` | StatusEvent | Contains information regarding the connected Wallet and Network |
+| `getActiveNetwork` | Network | Details of the connected network |
+| `listAccounts` | Account[] | Lists all accounts the user has access to |
+| `getPrimaryAccount` | Account | Returns the single account set as primary |
+| `signMessage` | string | Signs an arbitrary string message |
+| `prepareExecute` | void | Prepares, signs, and executes Daml commands |
+| `ledgerApi` | string | Proxies requests to the JSON Ledger API |
+
+**Events:**
+
+| Event | Payload | Description |
+| ----------------- | -------------------- | ------------------------------------------------------------------------------------- |
+| `accountsChanged` | AccountsChangedEvent | Emitted when accounts change; contains all accounts and indicates the primary account |
+| `statusChanged` | StatusEvent | Emitted when provider status changes (authentication, network connectivity) |
+| `txChanged` | TxChangedEvent | Announces changes to the lifecycle of initiated transactions |
+
+## Asynchronous dApp API (Async API)
+
+The **Asynchronous dApp API** is designed for server-side Wallets or Wallets deployed as remote services, where synchronous interactions are not feasible due to transport limitations (e.g., HTTP request timeouts) or the need for multi-step user authorization.
+
+This variant mirrors the Sync API but decomposes operations that require user interaction into multi-phase workflows. For such operations, the API returns a `userUrl` that directs the user to complete the required action (e.g., login or transaction approval), and emits the corresponding event once the action is finalized.
+
+**Key Differences from Sync API:**
+
+| Method | Output | Difference |
+| ---------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `connect` | { ...ConnectResult, userUrl: string } | If no prior connection exists, returns a `userUrl` pointing to a login facility. After successful login, a `connected` event is emitted. |
+| `prepareExecute` | { userUrl: string } | Returns a `userUrl` pointing to a review facility where the user can approve or decline signing. A `txChanged` event is emitted after the prepare phase completes. |
+
+**Additional Event:**
+
+| Event | Payload | Description |
+| ----------- | ----------- | -------------------------------------------------------------------------- |
+| `connected` | StatusEvent | Same payload as `statusChanged` but only emitted as part of the login flow |
+
+## Choosing Between Sync and Async API
+
+| Consideration | Sync API | Async API |
+| -------------------- | ---------------------------------------- | ------------------------------------ |
+| **Deployment Model** | Client-side (browser extension, desktop) | Server-side, remote custody services |
+| **User Interaction** | Direct, real-time | Via `userUrl` redirects |
+| **Blocking Calls** | Supported | Not supported |
+| **Transport** | postMessage, in-app bridges | HTTPS, SSE |
+
+Clients such as frontends that work against the Sync API **should** also work against a server exposing the Async API. The dApp SDK provides this compatibility by implementing the Sync API interface while relaying calls to an Async API server internally.
+
+## Provider Interface
+
+Both API variants are accessed through a **Provider** interface, following the pattern established by [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193):
+
+```typescript
+interface Provider {
+ request(args: {
+ method: string
+ params?: unknown[] | Record
+ }): Promise
+ on(event: string, listener: (...args: T[]) => void): Provider
+ emit(event: string, ...args: T[]): boolean
+ removeListener(event: string, listener: (...args: T[]) => void): Provider
+}
+```
+
+## Error Codes
+
+The dApp API adopts standardized error codes from [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) and [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474):
+
+| Code | Message | Meaning |
+| ------ | --------------------- | ---------------------------------------------------- |
+| 4001 | User Rejected Request | The user rejected the request |
+| 4100 | Unauthorized | The requested method/account has not been authorized |
+| 4200 | Unsupported Method | The Provider does not support the requested method |
+| 4900 | Disconnected | The Provider is disconnected from all chains |
+| 4901 | Chain Disconnected | The Provider is not connected to the requested chain |
+| -32700 | Parse error | Invalid JSON |
+| -32600 | Invalid request | JSON is not a valid request object |
+| -32601 | Method not found | Method does not exist |
+| -32602 | Invalid params | Invalid method parameters |
+| -32603 | Internal error | Internal JSON-RPC error |
+
+For the complete specification, refer to [CIP-0103](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md).
+
+{/* COPIED_END */}
diff --git a/docs-main/integrations/dapp-sdk/overview.mdx b/docs-main/integrations/dapp-sdk/overview.mdx
new file mode 100644
index 00000000..838be34d
--- /dev/null
+++ b/docs-main/integrations/dapp-sdk/overview.mdx
@@ -0,0 +1,54 @@
+---
+title: "Overview"
+description: "Introduction to the dApp SDK — a TypeScript library for connecting Canton Network dApps to wallets via CIP-103."
+---
+
+{/* COPIED_START source="wallet-gateway:docs/dapp-building/dapp-sdk/index.md" hash="a7fcee8d" */}
+
+The dApp SDK is a TypeScript library for building decentralized applications on the Canton Network. It provides a high-level interface for connecting to Canton wallets, managing accounts, signing messages, and executing transactions.
+
+The SDK implements the dApp API as defined in [CIP-0103](https://github.com/canton-foundation/cips/blob/main/cip-0103/cip-0103.md), establishing a vendor-neutral standard that enables any dApp to interoperate with any Canton-compatible wallet.
+
+**Overview**
+
+The dApp SDK decouples your application from wallet implementations, allowing users to choose their preferred wallet and signing provider. The SDK handles:
+
+- **Wallet Connectivity** - Connect, disconnect, and monitor connection status
+- **Account Management** - List accounts, get the primary account, and respond to account changes
+- **Transaction Signing** - Request user approval and signatures for Daml transactions
+- **Message Signing** - Sign arbitrary messages for authentication or verification
+- **Ledger API Access** - Proxy authenticated requests to the Canton JSON Ledger API
+- **Real-time Events** - Subscribe to status changes, account changes, and transaction lifecycle events
+
+**Architecture**
+
+The SDK provides two levels of abstraction:
+
+1. **dApp SDK** (recommended) - High-level methods like `sdk.connect()`, `sdk.listAccounts()`, and `sdk.prepareExecute()` for common operations
+2. **Provider API** - Low-level [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193)-compatible interface using `provider.request({ method, params })` for direct API access
+
+Both interfaces work with the same underlying dApp API, so you can mix and match as needed.
+
+**Transport Support**
+
+The SDK supports multiple transport mechanisms to connect to different wallet types:
+
+- **postMessage** - For browser extension wallets that inject a provider into the page
+- **HTTP/SSE** - For remote wallets and server-side wallet gateways
+
+The SDK automatically handles the transport layer, allowing your dApp to work with both local and remote wallets without code changes.
+
+**Provider Discovery**
+
+When using browser extension wallets, the SDK exposes an EIP-1193-compatible provider at `window.canton`, following the pattern established by Ethereum wallets. This enables wallet discovery and connection in browser environments. For extension authors, the SDK also supports namespace scanning, EIP-6963-style announcement events, and targeted `postMessage` routing. See the docs section [Wallet providers](/integrations/dapp-sdk/wallet-provider-integration).
+
+## Contents
+
+- [Installation](/integrations/dapp-sdk/download)
+- [Usage](/integrations/dapp-sdk/usage)
+- [Adapters & Discovery](/integrations/dapp-sdk/adapters-and-discovery)
+- [API Reference](/integrations/dapp-sdk/api-reference)
+- [Wallet providers](/integrations/dapp-sdk/wallet-provider-integration)
+- [Best Practices](/integrations/dapp-sdk/best-practices)
+
+{/* COPIED_END */}
diff --git a/docs-main/integrations/wallet-gateway/apis.mdx b/docs-main/integrations/wallet-gateway/apis.mdx
index 64521620..72886abb 100644
--- a/docs-main/integrations/wallet-gateway/apis.mdx
+++ b/docs-main/integrations/wallet-gateway/apis.mdx
@@ -3,7 +3,7 @@ title: "APIs"
description: "Wallet Gateway dApp API and User API reference"
---
-{/* COPIED_START source="wallet-gateway:docs/dapp-building/wallet-gateway/apis/index.md@82ec39c9" hash="dbda9001" */}
+{/* COPIED_START source="wallet-gateway:docs/dapp-building/wallet-gateway/apis/index.md" hash="c581db48" */}
The Wallet Gateway exposes two JSON-RPC 2.0 APIs: one for dApps interactions and one for user interactions. Both APIs use the same base URL but different paths.
@@ -28,7 +28,7 @@ Authorization: Bearer
**Full API Specification:**
-The complete OpenRPC specification is available at [openrpc-dapp-api.json](https://github.com/canton-network/wallet-gateway/blob/main/api-specs/openrpc-dapp-api.json).
+The complete OpenRPC specification is available at [openrpc-dapp-api.json](https://github.com/canton-network/wallet/blob/main/api-specs/openrpc-dapp-api.json).
## User API Reference
@@ -68,7 +68,7 @@ Most User API methods require authentication via JWT token. However, the followi
**Full API Specification:**
-The complete OpenRPC specification is available at [openrpc-user-api.json](https://github.com/canton-network/wallet-gateway/blob/main/api-specs/openrpc-user-api.json).
+The complete OpenRPC specification is available at [openrpc-user-api.json](https://github.com/canton-network/wallet/blob/main/api-specs/openrpc-user-api.json).
## Server-Sent Events (SSE) Support
diff --git a/docs-main/integrations/wallet-gateway/configuration-schema.mdx b/docs-main/integrations/wallet-gateway/configuration-schema.mdx
new file mode 100644
index 00000000..39bbb8b3
--- /dev/null
+++ b/docs-main/integrations/wallet-gateway/configuration-schema.mdx
@@ -0,0 +1,779 @@
+---
+title: "Configuration Schema"
+description: "Full JSON schema for the Wallet Gateway configuration file, generated by wallet-gateway-remote --config-schema."
+---
+
+{/* COPIED_START source="wallet-gateway:docs/dapp-building/wallet-gateway/configuration/schema.md" hash="42878326" */}
+
+The contents of this file was generated by the following command:
+
+```shell
+npx @canton-network/wallet-gateway-remote@latest --config-schema
+```
+
+```json
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "properties": {
+ "kernel": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "publicUrl": {
+ "description": "The public base URL of the gateway, if available (e.g. https://wallet.example.com). This determines what browsers will try to use to connect, and is useful when using reverse proxies. If omitted, this will be derived from the server configuration.",
+ "type": "string"
+ },
+ "clientType": {
+ "anyOf": [
+ {
+ "type": "string",
+ "const": "browser"
+ },
+ {
+ "type": "string",
+ "const": "desktop"
+ },
+ {
+ "type": "string",
+ "const": "mobile"
+ },
+ {
+ "type": "string",
+ "const": "remote"
+ }
+ ]
+ }
+ },
+ "required": ["id", "clientType"],
+ "additionalProperties": false
+ },
+ "server": {
+ "type": "object",
+ "properties": {
+ "port": {
+ "default": 3030,
+ "description": "The port on which the NodeJS service will listen. Defaults to 3030.",
+ "type": "number"
+ },
+ "dappPath": {
+ "default": "/api/v0/dapp",
+ "description": "The path serving the dapp API. Defaults /api/v0/dapp",
+ "type": "string"
+ },
+ "userPath": {
+ "default": "/api/v0/user",
+ "description": "The path serving the user API. Defaults /api/v0/user",
+ "type": "string"
+ },
+ "allowedOrigins": {
+ "default": "*",
+ "description": "Allowed CORS origins, typically corresponding to which external dApps are allowed to connect. Use \"*\" to allow all origins, or set an array of origin strings.",
+ "anyOf": [
+ {
+ "type": "string",
+ "const": "*"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "host": {
+ "deprecated": true,
+ "description": "The host interface the server binds to. Deprecated as the service always binds to the local machine network interface. Will be removed in a future release.",
+ "type": "string"
+ },
+ "tls": {
+ "deprecated": true,
+ "description": "Deprecated, this option no longer has any effect. Will be removed in a future release.",
+ "type": "boolean"
+ },
+ "requestSizeLimit": {
+ "default": "1mb",
+ "description": "The maximum size of incoming requests. Defaults to 1mb.",
+ "type": "string"
+ },
+ "requestRateLimit": {
+ "default": 10000,
+ "description": "The maximum number of requests per minute from a single IP address. Defaults to 10000.",
+ "type": "number"
+ },
+ "trustProxy": {
+ "default": false,
+ "description": "Express trust proxy setting used to resolve client IP addresses when running behind reverse proxies/load balancers. Set this correctly in production (for example 1 for a single trusted proxy hop). Defaults to false.",
+ "anyOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9007199254740991
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ "admin": {
+ "description": "The JWT claim (e.g. \"sub\") identifying the admin user. If set, requests with a matching claim will be granted admin privileges.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "port",
+ "dappPath",
+ "userPath",
+ "allowedOrigins",
+ "requestSizeLimit",
+ "requestRateLimit",
+ "trustProxy"
+ ],
+ "additionalProperties": false
+ },
+ "logging": {
+ "type": "object",
+ "properties": {
+ "level": {
+ "description": "The log level for the gateway. If omitted, defaults to info.",
+ "type": "string",
+ "enum": ["trace", "debug", "info", "warn", "error", "fatal"]
+ },
+ "format": {
+ "description": "The log format for the gateway. If omitted, defaults to pretty.",
+ "type": "string",
+ "enum": ["json", "pretty"]
+ }
+ },
+ "additionalProperties": false,
+ "description": "Optional logging configuration. If omitted, defaults will be used."
+ },
+ "store": {
+ "type": "object",
+ "properties": {
+ "connection": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "memory"
+ }
+ },
+ "required": ["type"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "sqlite"
+ },
+ "database": {
+ "type": "string"
+ }
+ },
+ "required": ["type", "database"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "postgres"
+ },
+ "host": {
+ "type": "string"
+ },
+ "port": {
+ "type": "number"
+ },
+ "user": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "database": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "host",
+ "port",
+ "user",
+ "password",
+ "database"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ },
+ "required": ["connection"],
+ "additionalProperties": false
+ },
+ "signingStore": {
+ "type": "object",
+ "properties": {
+ "connection": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "memory"
+ }
+ },
+ "required": ["type"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "sqlite"
+ },
+ "database": {
+ "type": "string"
+ }
+ },
+ "required": ["type", "database"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "const": "postgres"
+ },
+ "host": {
+ "type": "string"
+ },
+ "port": {
+ "type": "number"
+ },
+ "user": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "database": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "host",
+ "port",
+ "user",
+ "password",
+ "database"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ },
+ "required": ["connection"],
+ "additionalProperties": false
+ },
+ "bootstrap": {
+ "type": "object",
+ "properties": {
+ "idps": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "const": "self_signed"
+ },
+ "issuer": {
+ "type": "string"
+ }
+ },
+ "required": ["id", "type", "issuer"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "const": "oauth"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "configUrl": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "required": [
+ "id",
+ "type",
+ "issuer",
+ "configUrl"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ },
+ "networks": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "synchronizerId": {
+ "type": "string",
+ "minLength": 10,
+ "pattern": "::"
+ },
+ "identityProviderId": {
+ "type": "string"
+ },
+ "ledgerApi": {
+ "type": "object",
+ "properties": {
+ "baseUrl": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "required": ["baseUrl"],
+ "additionalProperties": false
+ },
+ "auth": {
+ "anyOf": [
+ {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "authorization_code"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "audience",
+ "scope",
+ "clientId"
+ ],
+ "additionalProperties": false,
+ "description": "Authorization code flow authentication configuration. This is used for browser-based application login."
+ },
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "client_credentials"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecret": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "audience",
+ "scope",
+ "clientId",
+ "clientSecret"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "self_signed"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecret": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "issuer",
+ "audience",
+ "scope",
+ "clientId",
+ "clientSecret"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ },
+ {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "authorization_code"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "audience",
+ "scope",
+ "clientId"
+ ],
+ "additionalProperties": false,
+ "description": "Authorization code flow authentication configuration. This is used for browser-based application login."
+ },
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "client_credentials"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecretEnv": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "audience",
+ "scope",
+ "clientId",
+ "clientSecretEnv"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "self_signed"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecretEnv": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "issuer",
+ "audience",
+ "scope",
+ "clientId",
+ "clientSecretEnv"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ ]
+ },
+ "adminAuth": {
+ "anyOf": [
+ {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "authorization_code"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "audience",
+ "scope",
+ "clientId"
+ ],
+ "additionalProperties": false,
+ "description": "Authorization code flow authentication configuration. This is used for browser-based application login."
+ },
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "client_credentials"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecret": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "audience",
+ "scope",
+ "clientId",
+ "clientSecret"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "self_signed"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecret": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "issuer",
+ "audience",
+ "scope",
+ "clientId",
+ "clientSecret"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ },
+ {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "authorization_code"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "audience",
+ "scope",
+ "clientId"
+ ],
+ "additionalProperties": false,
+ "description": "Authorization code flow authentication configuration. This is used for browser-based application login."
+ },
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "client_credentials"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecretEnv": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "audience",
+ "scope",
+ "clientId",
+ "clientSecretEnv"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "const": "self_signed"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecretEnv": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "method",
+ "issuer",
+ "audience",
+ "scope",
+ "clientId",
+ "clientSecretEnv"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "description",
+ "identityProviderId",
+ "ledgerApi",
+ "auth"
+ ],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": ["idps", "networks"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["kernel", "server", "store", "signingStore", "bootstrap"],
+ "additionalProperties": false
+}
+```
+
+{/* COPIED_END */}
diff --git a/docs-main/integrations/wallet-gateway/deployment.mdx b/docs-main/integrations/wallet-gateway/deployment.mdx
new file mode 100644
index 00000000..fdecbb19
--- /dev/null
+++ b/docs-main/integrations/wallet-gateway/deployment.mdx
@@ -0,0 +1,199 @@
+---
+title: "Deployment"
+description: "How to deploy the Wallet Gateway server in production."
+---
+
+{/* COPIED_START source="wallet-gateway:docs/dapp-building/wallet-gateway/deployment/index.md" hash="1e85642e" */}
+
+This section outlines some recommendations for production deployments of the Wallet Gateway service.
+
+The service is available in both Docker and Helm variants:
+
+- **Docker Registry**: `ghcr.io/digital-asset/wallet-gateway/docker/wallet-gateway:`
+- **Helm Repository**: `ghcr.io/digital-asset/wallet-gateway/helm/wallet-gateway:`
+
+Replace `` with the version you want to deploy. We don't currently publish `latest` tags. To determine which version to use, check either
+
+- The latest version displayed on the GHCR repo: https://github.com/digital-asset/wallet-gateway/pkgs/container/wallet-gateway%2Fdocker%2Fwallet-gateway
+- The version corresponding to the NPM package: https://www.npmjs.com/package/@canton-network/wallet-gateway-remote
+
+## Docker
+
+To run the Docker container, a configuration file must be supplied for the Wallet Gateway. If you don't have a configuration, you can generate a sample config to serve as a starting point:
+
+```shell
+# via Docker
+docker run --rm ghcr.io/digital-asset/wallet-gateway/docker/wallet-gateway: --config-example > config.json
+
+# alternatively, generate a sample config file via NPM
+npx @canton-network/wallet-gateway-remote@ --config-example > config.json
+```
+
+With the default config file, start the service:
+
+```shell
+docker run -p 3030:3030 \
+ -v ${PWD}/config.json:/app/config.json:ro \
+ ghcr.io/digital-asset/wallet-gateway/docker/wallet-gateway:
+```
+
+If all went well, the Wallet Gateway login page can be opened in a browser at http://localhost:3030.
+
+## Helm
+
+An official Helm chart is available for Kubernetes deployments. The full values.schema is [here](https://github.com/digital-asset/wallet-gateway/blob/main/charts/wallet-gateway/values.schema.json), but the important thing to note is that the Wallet Gateway is configured through the top-level `config:` key in `values.yaml`.
+
+The config is then specified as YAML, but otherwise uses the same schema as `config.json`.
+
+Signing providers can be configured directly in the chart values:
+
+```yaml
+signing:
+ # optional, define to enable blockdaemon integration -- or omit
+ blockdaemon:
+ apiUrl: 'http://localhost:5080/api/cwp/canton'
+ apiKeyRef:
+ name: 'blockdaemon-creds'
+ key: 'api-key'
+ # optional, define to enable fireblocks integration -- or omit
+ fireblocks:
+ apiKeyRef:
+ name: 'fireblocks-creds'
+ key: 'fb-api-key'
+ secretRef:
+ name: 'fireblocks-creds'
+ key: 'fb-secret'
+```
+
+The chart also provides a helper for providing OAuth client secrets directly from Kubernetes secrets. This is done by specifying a mapping between a custom environment variable name and the secret reference:
+
+```yaml
+oauthSecrets:
+ # map a kubernetes secret to a Wallet Gateway network auth config
+ MY_OAUTH2_CLIENT_SECRET:
+ secretRef:
+ name: 'my-oauth'
+ key: 'client-secret'
+# ...
+
+config:
+ # ...
+ networks:
+ - id: 'my-network'
+ # ...
+ adminAuth:
+ # ...
+ # should correlate to a secret provided in oauthSecrets
+ clientSecretEnv: 'MY_OAUTH2_CLIENT_SECRET'
+```
+
+## Configuration
+
+The [Configuration](/integrations/wallet-gateway/configuration) section contains a complete breakdown of the options. Please read through that page first, then return here.
+
+The following config is incomplete, but highlights specific fields of note to consider for a production deployment:
+
+```yaml
+kernel:
+ # Set the publically accessible URL that users would use to connect to the deployed Wallet Gateway.
+ # Subpath routing is also supported
+ publicUrl: 'https://wallet.example.com/subpath'
+server:
+ # In a Helm/k8s setup, we recommend leaving the port set to the default `3030` value,
+ # and routing the service internally from your Ingress/LoadBalancer (exposed on 443) to the pod's port.
+
+ # We strongly recommend TLS termination of your cluster, so that the Wallet Gateway is accessible to clients over `https`.
+ port: 3030
+
+ # Set this to an array of origins corresponding to the set of web dApps that are allowed to call the dApp API.
+ allowedOrigins:
+ - 'https://dapp1.example.com'
+ - 'https://dapp2.example.com'
+
+ # The default value (`5mb`) may need to be bumped for heavy use (large contract payloads may exceed this).
+ requestSizeLimit: '5mb'
+
+ # Default is `10000` requests / second / IP address. Bump if encountering HTTP 429 errors during regular use.
+ requestRateLimit: 10000
+bootstrap:
+ networks:
+ - adminAuth:
+ # For PRODUCTION, we recommend providing OAuth secrets for network admins via the environment.
+ # This allows the secret to be stored in a secure secrets manager, and injected into the container at runtime.
+ # This field defines the name of the environment variable to use for this network.
+ clientSecretEnv: 'OAUTH2_CLIENT_SECRET'
+```
+
+### Environment Variables
+
+Aside from the dynamic environment variables supported in config (`networks[].adminAuth.clientSecretEnv`), there are a few static environment variables available to configure external signing providers:
+
+**Fireblocks**
+
+- `FIREBLOCKS_API_KEY`: The API key for the Fireblocks integration
+- `FIREBLOCKS_SECRET`: The secret for the Fireblocks integration
+
+**Blockdaemon**
+
+- `BLOCKDAEMON_API_KEY`: The API key for the Blockdaemon integration
+- `BLOCKDAEMON_API_URL`: The URL for the Blockdaemon API
+
+See [Signing Providers](/integrations/wallet-gateway/signing-providers) for more information.
+
+## Database Persistence
+
+### SQLite
+
+The default config uses `sqlite` as a persistent data store for the Wallet Gateway. To prevent the data from being reset across container restarts, the sqlite files must be mounted to a volume.
+
+First, configure the stores to point somewhere in the container:
+
+```yaml
+# config YAML for helm, or equivalent config.json
+signingStore:
+ connection:
+ type: "sqlite",
+ database: "/data/signing_store.sqlite"
+store:
+ connection:
+ type: "sqlite",
+ database: "/data/store.sqlite"
+```
+
+Then start the container with the volume mount
+
+```shell
+docker run -p 3030:3030 \
+ -v ${PWD}/config.json:/app/config.json:ro \
+ -v ${PWD}/data:/data \
+ ghcr.io/digital-asset/wallet-gateway/docker/wallet-gateway:
+```
+
+### PostgreSQL
+
+Alternatively, the Wallet Gateway can be configured to use a separate PostgreSQL connection:
+
+```yaml
+# config YAML for helm, or equivalent config.json
+store:
+ connection:
+ type: "postgres",
+ host: "",
+ port: 5432,
+ database: "",
+ user: "",
+ password: ""
+```
+
+## Logging
+
+JSON logging can be enabled via the `--log-format` CLI flag (values: `"pretty" (default) | "json"`):
+
+```shell
+docker run -p 3030:3030 \
+ -v ${PWD}/config.json:/app/config.json:ro \
+ ghcr.io/digital-asset/wallet-gateway/docker/wallet-gateway: \
+ --log-format=json
+```
+
+{/* COPIED_END */}
diff --git a/docs-main/integrations/wallet-gateway/overview.mdx b/docs-main/integrations/wallet-gateway/overview.mdx
new file mode 100644
index 00000000..3ccc16ce
--- /dev/null
+++ b/docs-main/integrations/wallet-gateway/overview.mdx
@@ -0,0 +1,45 @@
+---
+title: "Overview"
+description: "Introduction to the Wallet Gateway — a server that mediates between dApps, Canton validators, and signing providers."
+---
+
+{/* COPIED_START source="wallet-gateway:docs/dapp-building/wallet-gateway/index.md" hash="112a68f0" */}
+
+The Wallet Gateway is a JavaScript/TypeScript-based server that facilitates secure communication between decentralized applications (dApps), Canton Validator nodes, and Wallet Providers. It acts as a mediator, enabling seamless transaction signing and ledger interactions while maintaining the privacy and security guarantees of the Canton protocol.
+
+
+This guide is under active development, not all sections are complete and sections will be added and adjusted over time.
+
+
+**What is Wallet Gateway?**
+
+The Wallet Gateway enables transparent interaction between a dApp, Validator Node, and a Wallet Provider. Unlike public permissionless blockchains where a total state is shared amongst all nodes, Canton's unique approach to security and privacy results in fractured states shared amongst selected Validator nodes. Simply showing ownership of an associated private key does not reveal your entire financial data to a counter-party (such as a dApp).
+
+**Wallet Gateway aims to**
+
+- Maintain the high-level of security and trust inherent in the Canton Protocol
+- Enable seamless communication between a dApp, Validator Node, and Signature Provider, similar in experience to other blockchains
+- Provide transparency against malicious dApps, Validator Nodes, or Signature Providers
+- Create a standardized communication framework that allows anybody to extend or integrate with the Wallet Gateway
+
+**Key Features**
+
+- **JSON-RPC APIs**: Two distinct APIs for dApp and user interactions
+- **Multiple Signing Providers**: Support for participant-based signing, internal signing, Dfns, Fireblocks, and Blockdaemon
+- **Flexible Identity Providers**: Support for OAuth 2.0 and self-signed JWT tokens
+- **Network Management**: Configure and manage multiple Canton networks
+- **Session Management**: Secure session handling with JWT authentication
+- **Web UI**: User-friendly web interface for wallet management
+- **Multiple Storage Backends**: Support for in-memory, SQLite, and PostgreSQL storage
+
+## Contents
+
+- [Getting Started](/integrations/wallet-gateway/download)
+- [Configuration](/integrations/wallet-gateway/configuration)
+- [Usage](/integrations/wallet-gateway/usage)
+- [APIs](/integrations/wallet-gateway/apis)
+- [Signing Providers](/integrations/wallet-gateway/signing-providers)
+- [Deployment](/integrations/wallet-gateway/deployment)
+- [Troubleshooting](/integrations/wallet-gateway/troubleshooting)
+
+{/* COPIED_END */}
diff --git a/docs-main/integrations/wallet-gateway/signing-providers.mdx b/docs-main/integrations/wallet-gateway/signing-providers.mdx
index 09cf2211..8b7ebfd5 100644
--- a/docs-main/integrations/wallet-gateway/signing-providers.mdx
+++ b/docs-main/integrations/wallet-gateway/signing-providers.mdx
@@ -1,9 +1,9 @@
---
title: "Signing Providers"
-description: "Wallet Gateway signing provider integrations"
+description: "Wallet Gateway signing provider integrations (participant, internal, Fireblocks, Blockdaemon)"
---
-{/* COPIED_START source="wallet-gateway:docs/dapp-building/wallet-gateway/signing-providers/index.md@82ec39c9" hash="ce58d241" */}
+{/* COPIED_START source="wallet-gateway:docs/dapp-building/wallet-gateway/signing-providers/index.md" hash="0e02eba4" */}
The Wallet Gateway supports multiple signing providers that handle cryptographic key management and transaction signing. Each provider has different use cases and security characteristics.
@@ -25,8 +25,9 @@ This provider is automatically available when a `signingStore` is configured in
**Security Considerations:**
-> [!IMPORTANT]
-> Private keys are stored in the database. If the database is compromised, all keys are at risk. Use only in non-production environments.
+
+Private keys are stored in the database. If the database is compromised, all keys are at risk. Use only in non-production environments.
+
## Participant-Based Signing
@@ -52,7 +53,7 @@ Fireblocks is a third-party crypto custody service provider that offers enterpri
**Setup:**
-1. Complete steps 1-3 from the [Fireblocks signing documentation](https://github.com/canton-network/wallet-gateway/tree/main/core/signing-fireblocks)
+1. Complete steps 1-3 from the [Fireblocks signing documentation](https://github.com/canton-network/wallet/tree/main/core/signing-fireblocks)
2. Supply an environment variable named `FIREBLOCKS_API_KEY` containing your Fireblocks API key (from the `API User (ID)` column in the Fireblocks API users table).