Skip to main content
This page describes common patterns for integrating Canton Network building blocks into applications. These patterns help you design effective integrations while respecting Canton’s privacy model.

Pattern Overview

Wallet Integration Pattern

Use Case

Add Canton Coin management to your application, allowing users to:
  • View their CC balance
  • Transfer CC to other parties
  • Top up traffic for transactions

Architecture

Key Considerations

ConsiderationApproach
AuthenticationIntegrate with your auth system; map users to parties
Balance displayQuery via Wallet SDK; cache appropriately
TransfersSubmit via Ledger API; handle async confirmation
Error handlingHandle insufficient balance, network errors

Privacy Implications

  • Users see only their own balance
  • Transfer details visible only to sender and receiver
  • Your application backend sees what it’s authorized to see

Token Operations Pattern

Use Case

Create, manage, and transfer tokens following the Canton Token Standard (CIP-0056).

Architecture

Implementation Approach

-- Implement token standard interfaces
template MyToken
  with
    issuer : Party
    holder : Party
    amount : Decimal
  where
    signatory issuer
    observer holder

    -- Implement standard holding interface
    interface instance HoldingInterface for MyToken where
      view = HoldingView with
        custodian = issuer
        owner = holder
        amount = amount

    -- Standard transfer choice
    choice Transfer : ContractId MyToken
      with
        newHolder : Party
      controller holder
      do
        create this with holder = newHolder

Key Considerations

ConsiderationApproach
InteroperabilityFollow CIP-0056 for wallet compatibility
AuthorizationDefine clear signatory/controller roles
PrivacyToken balances visible only to holders

Application Integration Pattern

Use Case

Integrate with other Canton Network applications, such as:
  • DeFi protocols
  • Identity services
  • Data feeds

Architecture

Integration Approaches

ApproachWhen to Use
On-ledgerMulti-party workflows requiring atomic execution
Off-ledger APIRead-only queries, non-transactional operations
HybridCombine both for complete integration

Key Considerations

ConsiderationApproach
Interface compatibilityUse published Daml interfaces
AuthorizationUnderstand party requirements
PrivacyKnow what data is shared through composition
VersioningHandle contract upgrades

Data Access Pattern

Use Case

Query ledger data for reporting, analytics, or application state.

Options

MethodUse CasePerformance
Ledger APIReal-time queries, streamingGood
PQSComplex queries, analyticsBest for reads
Transaction treesHistorical data, auditDepends on volume

Architecture with PQS

PQS connects to the participant node via the Ledger API to receive transaction updates, then stores the data in its own PostgreSQL database for querying.

Key Considerations

ConsiderationApproach
Query complexitySimple: Ledger API; Complex: PQS
Latency requirementsReal-time: Ledger API; Batch: PQS
Data volumeHigh volume: PQS with indexing
Privacy scopeOnly query data for authorized parties

Privacy-Aware Design

All integration patterns must account for Canton’s privacy model:

Design Principles

PrincipleApplication
Minimal visibilityRequest only necessary observer rights
Party designDon’t create parties unnecessarily
Divulgence awarenessUnderstand what composing contracts reveals
Audit considerationPlan for audit visibility from the start

Common Mistakes

MistakeImpactSolution
Over-observingUnnecessary data exposureMinimize observers
Public queriesExpecting global stateQuery party-scoped data
Ignoring divulgenceUnintended data sharingMap transaction composition

Error Handling Patterns

Integrations should handle common error scenarios:
ErrorCauseHandling
Insufficient trafficNot enough CC for feesPrompt for top-up
Authorization failureParty not authorizedCheck party setup
TimeoutNetwork or validator issuesRetry with backoff
Contract not foundArchived or never existedRefresh state

Retry Strategy

async function submitWithRetry<T>(command: Command, maxRetries = 3): Promise<T> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await ledgerApi.submit(command);
    } catch (error) {
      if (isRetryable(error) && attempt < maxRetries - 1) {
        await sleep(Math.pow(2, attempt) * 1000);
        continue;
      }
      throw error;
    }
  }
  throw new Error("Max retries exceeded");
}

Next Steps