@canton-network/dapp-sdk
v1.5.1
Published
Browser SDK for dApp development on the Canton Network
Keywords
Readme
dApp SDK
@canton-network/dapp-sdk — TypeScript SDK for building decentralized applications on the Canton Network. Connect users to Canton wallets, manage accounts, sign messages, and execute transactions — all through a vendor-neutral interface defined by CIP-0103.
[!NOTE] Migration guides for each release are published in Discussions.
Features
- Wallet Discovery — Remote gateways, EIP-6963-style
canton:announceProviderevents, and pluggable adapters - Wallet Picker UI — Built-in, framework-agnostic Web Component that lets users choose a wallet, enter custom gateway URLs, and manage recently used connections
- Wallet Connectivity — Connect, disconnect, and monitor connection status
- Account Management — List accounts and respond to account changes
- Transaction Execution — Request user approval and signatures for Daml transactions
- 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
- Multi-transport — HTTP/SSE for remote Wallet Gateways,
postMessagefor browser extension wallets - Provider Interface — EIP-1193-style CIP-103 provider via
getConnectedProvider()afterconnect()
Installation
npm install @canton-network/dapp-sdkpnpm add @canton-network/dapp-sdkQuick Start
The fastest way to get going is through the module-level convenience API. It manages a singleton DappClient behind the scenes, opens the wallet picker, and handles adapter registration for you.
import * as sdk from '@canton-network/dapp-sdk'
// Opens the wallet picker and connects to the selected wallet
const result = await sdk.connect()
console.log(result.isConnected)
// List the user's accounts (parties)
const accounts = await sdk.listAccounts()
// Execute a transaction
await sdk.prepareExecute({
commands: [
{
CreateCommand: {
templateId: '#MyApp:MyModule:MyTemplate',
createArguments: { owner: accounts[0].partyId },
},
},
],
})
// Listen for real-time updates
sdk.onTxChanged((tx) => {
console.log('Transaction update:', tx)
})
// Disconnect when done
await sdk.disconnect()Architecture
The SDK is built around three layers:
┌──────────────────────────────────────────────┐
│ DappClient │
│ Thin wrapper: typed RPC helpers, events, │
│ session persist │
├──────────────────────────────────────────────┤
│ DiscoveryClient │
│ Adapter registry, session restore, │
│ wallet picker integration │
├──────────────────────────────────────────────┤
│ ProviderAdapter implementations │
│ ExtensionAdapter (announce protocol) │
│ (browser / postMessage) │
│ RemoteAdapter (HTTP/SSE gateway) │
└──────────────────────────────────────────────┘Wallet providers
Wallet and extension authors: see Wallet providers (discovery) in the dApp Building docs for how to appear in the picker (RemoteAdapter, canton:announceProvider, and additionalAdapters).
Usage
Option A: Module-level API (recommended for most apps)
Import the SDK as a namespace. The connect() function opens the built-in wallet picker, registers available adapters, and returns a ConnectResult.
import * as sdk from '@canton-network/dapp-sdk'
import { RemoteAdapter } from '@canton-network/dapp-sdk'
await sdk.connect()
const status = await sdk.status()You can supply additional adapters at connect time:
await sdk.connect({
additionalAdapters: [
new RemoteAdapter({
name: 'My Gateway',
rpcUrl: 'https://gateway.example.com/api/json-rpc',
}),
],
})Option B: DappClient with DiscoveryClient
For more control over adapter registration and the connection flow, use DiscoveryClient directly and pass the resulting provider to DappClient.
import {
DappClient,
DiscoveryClient,
RemoteAdapter,
} from '@canton-network/dapp-sdk'
const discovery = await DiscoveryClient.create({
adapters: [
new RemoteAdapter({
name: 'Splice Wallet Gateway',
rpcUrl: 'https://gateway.example.com/api/json-rpc',
}),
],
})
await discovery.connect() // opens the picker if configured
const session = discovery.getActiveSession()!
const client = new DappClient(session.provider, {
providerType: session.adapter.type,
})
const status = await client.status()Option C: DappClient with a provider directly
If you already have a Provider<DappRpcTypes> (for example from your own adapter), you can skip discovery entirely.
import { DappClient, RemoteAdapter } from '@canton-network/dapp-sdk'
const provider = new RemoteAdapter({
name: 'Splice Wallet Gateway',
rpcUrl: 'https://gateway.example.com/api/json-rpc',
}).provider()
const client = new DappClient(provider)
const result = await client.connect()API Reference
DappClient
| Method | Returns | Description |
| ------------------------------- | ----------------------------- | ------------------------------------ |
| connect() | ConnectResult | Initiate connection via the provider |
| disconnect() | void | Disconnect and clear local state |
| status() | StatusEvent | Current connection status |
| listAccounts() | ListAccountsResult | List the user's accounts (parties) |
| prepareExecute(params) | null | Submit a transaction for signing |
| prepareExecuteAndWait(params) | PrepareExecuteAndWaitResult | Submit and wait for completion |
| ledgerApi(params) | LedgerApiResult | Proxy a Ledger API request |
| open() | void | Open the wallet UI |
| getProvider() | Provider | Access the underlying provider |
| onStatusChanged(listener) | void | Subscribe to status changes |
| onAccountsChanged(listener) | void | Subscribe to account changes |
| onTxChanged(listener) | void | Subscribe to transaction changes |
DappClientOptions
| Option | Type | Default | Description |
| -------------- | -------------- | ---------- | ------------------------------------------------------------------------- |
| providerType | ProviderType | 'remote' | Affects open() routing ('browser' uses postMessage, others use popup) |
DiscoveryClient
| Method | Description |
| -------------------------------- | ----------------------------------------------------------------------------- |
| create(config) | Create an initialized client and attempt session restore |
| registerAdapter(adapter) | Add a ProviderAdapter at runtime |
| listAdapters() | List registered adapters |
| connect(providerId?) | Connect to a specific adapter or open the picker |
| disconnect() | Disconnect the active session |
| getActiveSession() | Get the current ActiveSession or null |
| on(event, handler) | Listen for discovery:connected, discovery:disconnected, discovery:error |
| removeListener(event, handler) | Remove an event listener |
Built-in Adapters
| Adapter | Provider Type | Transport | Description |
| ------------------ | ------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ExtensionAdapter | 'browser' | postMessage | Browser extensions discovered via canton:announceProvider (Wallet providers guide). |
| RemoteAdapter | 'remote' | HTTP/SSE | CIP-103 Wallet Gateways over the network. |
Documentation
Full documentation, including detailed usage guides, API reference, and configuration for the Wallet Gateway:
- dApp Building Guide
- dApp SDK Documentation
- Wallet providers (discovery)
- API Specifications (OpenRPC)
- Example dApps
