Canton Integration Guide

This guide walks through integrating Chainlink Data Streams to consume cryptographically verified market data within your Canton application.

Understanding the Canton Network

Unlike traditional blockchains where all state is replicated across all nodes, the Canton Network is a privacy-preserving blockchain that distributes state and transactions only to parties with a legitimate need to see them. This "network of networks" architecture allows validators to store and process only their portion of the ledger, designed to balance privacy and scalability with the decentralization model of a public blockchain. Learn more about the Canton Network.

Canton Network applications are built on infrastructure that manages ledger state through two types of nodes:

  • Validator Nodes store and validate the portion of the ledger they are entitled to see
  • Synchronizer Nodes coordinate transaction commits to prevent double-spends
  • Access to ledger data is managed through Daml parties—identifiers for cryptographic keys that represent app providers and app users
  • Each Daml party is hosted on a Validator Node, which stores their data and validates transactions on their behalf

For Chainlink Data Streams integration, this party-based model means:

  • Your application needs a Daml party to verify reports
  • The Chainlink team grants your Daml party observer access to the VerifierConfig contract, which contains the oracle public keys required for signature verification
  • When you verify a Chainlink Data Streams report, your Daml application exercises a choice on the Verifier contract
  • Verification occurs within your Canton ledger context using the configuration your Daml party can observe

How It Works

Reports are generated off-chain by Chainlink's OCR (Off-Chain Reporting) protocol and contain f+1 cryptographic signatures from oracle nodes. Your Canton application verifies these signatures before consuming the data.

Key components:

  • Verifier - A stateless contract that performs cryptographic signature verification against oracle public keys. You create and own this contract.
  • VerifierConfig - A party-specific contract holding the oracle public keys and fault tolerance configuration. Chainlink issues this to you after onboarding.

The Verifier is intentionally stateless and separated from configuration management—this allows you to create your own Verifier instances while using the Chainlink-issued VerifierConfig for the oracle keys.

Prerequisites

To get started with your Data Streams integration on the Canton Network, you need:

  • Access to a Canton participant node
  • Ability to upload DAR packages to your Canton participant node
  • Familiarity with Daml contract development
  • Access to the Chainlink Data Streams API

Tutorial

Obtain Data Streams Access

Contact Chainlink to request access to the Data Streams API. You will receive:

  • API credentials (Client ID and Client Secret)
  • Access to the Data Streams REST/WebSocket endpoints
  • Documentation for fetching signed reports

For more information on Data Streams, see the official Chainlink Data Streams documentation.

Download Daml Contracts

Download the verification contracts from the GitHub releases page:

https://github.com/smartcontractkit/data-streams-canton/releases

The release includes the following DAR packages:

PackageDescription
common-1.0.0.darShared utilities and data types
domain-1.0.0.darDomain-specific types for Data Streams
verifier-config-1.0.0.darConfiguration contract for oracle keys
verifier-1.0.0.darVerification engine for validating reports

Upload Contracts to Canton

Upload the DAR packages to your Canton participant node:

  • common-1.0.0.dar
  • domain-1.0.0.dar
  • verifier-config-1.0.0.dar
  • verifier-1.0.0.dar

For guidance on uploading DAR packages, see the Canton documentation on deploying Daml code.

Request Configuration

Once the contracts are uploaded, provide your Canton Party ID to the Chainlink team. This is the party identifier that will be verifying reports within your application.

The Chainlink team needs this to:

  • Add your party as an observer on the VerifierConfig contract
  • Enable your party to use the verification functionality

Your Canton Party ID is typically in the format party::namespace and can be retrieved from your Canton participant admin console or via the Ledger API.

Receive VerifierConfig

After onboarding, the Chainlink team will issue a VerifierConfig contract to your party. This contract contains:

  • Oracle public keys for signature verification
  • Fault tolerance parameter (f) defining the required signature threshold (f+1 signatures required)
  • Configuration digest for active oracle sets

Verify Reports

With everything in place, you can now verify Data Streams reports:

Fetch a signed report from the Data Streams API

Choose from the available streams at https://data.chain.link/streams. Use the Data Streams SDK or REST API to fetch reports. The API returns hex-encoded signed reports containing:

  • The report payload (price data, timestamps, etc.)
  • f+1 cryptographic signatures from Chainlink oracle nodes

Learn more about how to fetch and decode reports with the Go, Rust, and TypeScript SDKs in the Fetch and decode reports tutorial.

Submit to your Canton application

Your Daml application calls the Verify choice on the Verifier contract. First, import the required modules:

import Verifier
import DA.Crypto.Text (BytesHex)

Then create or reference a Verifier instance and call the Verify choice:

-- Create a Verifier instance (stateless, can be reused)
verifierCid <- submit myParty $ createCmd Verifier with
  owner = myParty
  observers = []

-- Hex-encoded signed report from the Data Streams API
let signedReport : BytesHex = "0x..."

-- Verify the report using your VerifierConfig Contract ID
reportData <- submit myParty $ exerciseCmd verifierCid Verify with
  configCid = myVerifierConfigCid
  signedReportBytes = signedReport
  sender = myParty

Use the verified data

If verification succeeds, reportData contains the hex-encoded report payload. You can parse this data for use in your application. For example, to decode a V3 crypto report:

import ReportDataV3 (parseReportDataV3)

-- Parse the verified report payload
let v3 = parseReportDataV3 reportData

-- Access the decoded report fields
let feedId = v3.feedId                             -- Stream identifier
let benchmarkPrice = v3.benchmarkPrice             -- Price with 18 decimals
let bid = v3.bid                                   -- Bid price
let ask = v3.ask                                   -- Ask price
let validFromTimestamp = v3.validFromTimestamp     -- Report valid from
let expiresAt = v3.expiresAt                       -- Report expiration
let observationsTimestamp = v3.observationsTimestamp

Important Considerations

  • Config Updates: When oracle configurations change, you'll receive a new VerifierConfig Contract ID. Your application must look up the latest Contract ID when verifying reports.
  • Observer Access: You must be explicitly added as an observer to query VerifierConfig. Verification results are only visible to the verifying party and contract observers.
  • Report Freshness: Always check report timestamps to ensure data isn't stale.
  • Report Feed ID: Always verify the feed ID in the report matches the expected stream to ensure you're using the correct data.
  • Error Handling: Handle verification errors gracefully in your application.

What's next

Get the latest Chainlink content straight to your inbox.