Skip to main content

Documentation Index

Fetch the complete documentation index at: https://cantonfoundation-add-app-development-module-579.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

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, 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.

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. 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, 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-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 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.
    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).
    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.
    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.
    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.
    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.

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