canton-network-docs/dApp SDKdApp SDK Integration Guide
Wallet Provider Integration
This guide is for wallet and browser-extension authors who want their product to show up in the wallet discovery / picker that the dApp SDK opens onDocumentation Index
Fetch the complete documentation index at: https://docs.canton.network/llms.txt
Use this file to discover all available pages before exploring further.
connect().
End-user dApps pull in adapters automatically; wallets choose one or more of the integration paths below.
Discovery runs in the browser (or any environment where window exists).
The SDK merges these sources, deduplicates by providerId where applicable, and then passes the list to the wallet picker UI.
What the SDK registers by default on connect()
RemoteAdapterentries — Built-in and configured Wallet Gateway URLs (HTTP/SSE CIP-0103 bridge).- Injected providers from
window(namespace scan) — See Injected / namespaced providers. These are registered without running adapterdetect(); if the scan finds a provider-shaped object, a picker entry is added (including a directwindow.cantonprovider). - Announced extensions — See Announcement events (EIP-6963-style). Each announcement becomes an
ExtensionAdapterwith a distinctproviderIdand optionaltarget;detect()must succeed (extension visible and handshake OK).
additionalAdapters (or configure DiscoveryClient directly) to register more ExtensionAdapter, RemoteAdapter, or custom adapters.
Remote Wallets (RemoteAdapter)
Server-side wallets (such as the Wallet Gateway) are not injected into the page; they are listed as remote entries with an RPC URL.
Bundled defaults come from the SDK’s gateway list; dApps can add more by calling init({ additionalAdapters: [...] }) before connect(), or by constructing DiscoveryClient with extra RemoteAdapter instances.
Injected / namespaced providers
The SDK scans global roots onwindow for objects that look like a CIP-0103 Provider (request, on, emit, removeListener).
Roots scanned today (each entry is optional; missing roots are skipped):
| Global root | Purpose |
|---|---|
window.canton | Common CIP-0103 global; may be a provider or a bag of named providers (see below). |
window.<root> itself is provider-shaped, discovery adds one entry. Its stable id is the root name (e.g. canton), and the picker uses an adapter with providerId browser:<id> (e.g. browser:canton).
Namespaced bag: If window.<root> is a plain object, each own property whose value is provider-shaped becomes a separate entry with id <root>.<key> (e.g. canton.myBrand), i.e. providerId browser:canton.myBrand.
Why namespace: window.canton.myWallet allows multiple extensions or scripts to expose distinct providers without overwriting a single shared window.canton reference.
If nothing provider-shaped appears on a scanned root, the picker will not list your wallet until you announce or register an ExtensionAdapter via additionalAdapters (see below—e.g. when you only bridge over postMessage).
Announcement events (EIP-6963-style)
Ethereum’s EIP-6963 uses a request/announce event pair so each wallet can identify itself without fighting over one global. The dApp SDK uses the same pattern with Canton-specific event names:| Direction | Event name | Payload (detail) |
|---|---|---|
| dApp → wallets | canton:requestProvider | Optional; may be {} |
| Wallet → dApp | canton:announceProvider | id (string, required), name (string, required), optional icon, optional target |
- After the dApp dispatches
canton:requestProvider, wallets shoulddispatchEvent(new CustomEvent('canton:announceProvider', { detail: { ... } }))onwindow. - The SDK collects announcements for a short window (~300 ms by default), then registers one
ExtensionAdapterperidwithproviderIdbrowser:ext:<id>, displayname, and routingtargetdefaulting toidwhen omitted. - The extension must still pass
detect(): ready/ack orwindow.cantonas implemented inExtensionAdapter, and if you usetarget, the content script should only handleSPLICE_WALLET_*/ RPC traffic whosetargetmatches (so the correct extension answers).
Explicit registration by the dApp (additionalAdapters)
A wallet can ship instructions for dApps to register a dedicated adapter:
providerId string and the same target your extension filters on for WindowTransport / splice messages.
Summary: choose your integration
| Goal | Recommended approach |
|---|---|
Single extension, provider-shaped window.canton | Namespace scan (injected) + CIP-0103 postMessage / inject |
Multiple extensions or avoid window.canton collisions | canton:announceProvider + target, and/or window.canton.<brand> namespaced providers |
| In-page script / non-extension inject | Place provider at window.<root> or window.<root>.<name> under a scanned root |
| Hosted gateway | RemoteAdapter with public RPC URL |