# Canton Integration Guide
Source: https://docs.chain.link/data-streams/canton-integration

> For the complete documentation index, see [llms.txt](/llms.txt).

import DataStreams from "@features/data-streams/common/DataStreams.astro"

> **CAUTION: Provider Integration**
>
> If you're interested in making your Canton contract data available as a Chainlink Data Stream, you can integrate as a
> data provider. This enables other parties to consume your data with cryptographic guarantees. [Contact the Chainlink
> team](https://chain.link/contact?ref_id=datastreams) to discuss provider integration options, including use cases such
> as Proof of Reserve, Exchange Data, DeFi Yields, and Custom Data.

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](https://docs.digitalasset.com/overview/3.4/index.html) 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](https://docs.digitalasset.com/build/3.4/overview/index.html).

Canton Network applications are built on infrastructure that [manages ledger state through two types of nodes](https://docs.digitalasset.com/build/3.3/overview/key_concepts.html#canton-network-infrastructure):

- **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](https://docs.digitalasset.com/build/3.3/overview/key_concepts.html#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.

(Image: Image)

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

> **NOTE: Canton vs EVM**
>
> Unlike EVM where contract state is publicly visible and updated in-place, Canton uses an immutable contract model
> where updates archive the old contract and create a new one with a new Contract ID. This means verification results
> are only visible to parties with observer access, and you must track the current `VerifierConfig` Contract ID as
> configurations change.

## Prerequisites

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

- Access to a [Canton participant node](https://docs.digitalasset.com/operate/3.4/overview/index.html)
- Ability to [upload DAR packages to your Canton participant node](https://docs.digitalasset.com/operate/3.4/howtos/operate/packages/packages.html)
- Familiarity with [Daml contract development](https://docs.digitalasset.com/build/3.5/reference/smart-contracts/index.html)
- Access to the Chainlink Data Streams API
  - [Contact us to request access and receive API credentials](https://chain.link/contact?ref_id=datastreams)

## Tutorial

### Obtain Data Streams Access

[Contact Chainlink](https://chain.link/contact?ref_id=datastreams) 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

For more information on Data Streams, see the [official Chainlink Data Streams documentation](/data-streams).

### Download Daml Contracts

Download the verification contracts from the GitHub releases page:

**[https://github.com/smartcontractkit/data-streams-canton/releases](https://github.com/smartcontractkit/data-streams-canton/releases)**

The release includes the following DAR packages:

| Package                     | Description                                |
| --------------------------- | ------------------------------------------ |
| `common-1.0.0.dar`          | Shared utilities and data types            |
| `domain-1.0.0.dar`          | Domain-specific types for Data Streams     |
| `verifier-config-1.0.0.dar` | Configuration contract for oracle keys     |
| `verifier-1.0.0.dar`        | Verification 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](https://docs.digitalasset.com/build/3.3/sdlc-howtos/deploy-daml-code/index.html).

### 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](https://docs.digitalasset.com/build/3.3/component-howtos/ledger-api/index.html).

### 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

> **CAUTION: Important**
>
> The `VerifierConfig` contract is actively maintained by Chainlink. When oracle configurations change, Chainlink will
> update the contract which will generate a new Contract ID. It is important that you look up the latest Contract ID
> when verifying reports.

### 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 in the [Streams Overview page](/data-streams/reference/report-schema-overview). Use the [Data Streams SDK](/data-streams/reference/data-streams-api/go-sdk) or [REST API](/data-streams/reference/data-streams-api/interface-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](/data-streams/tutorials/go-sdk-fetch) tutorial.

#### Submit to your Canton application

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

```haskell
import Verifier
import DA.Crypto.Text (BytesHex)
```

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

```haskell
-- 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:

```haskell
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
```

> **NOTE: Reference Examples**
>
> The example decoding modules (`ReportDataV3.daml`, `HexToDecimal.daml`) are provided as unaudited reference
> implementations in the [examples
> directory](https://github.com/smartcontractkit/data-streams-canton/tree/main/examples). Review and adapt them for your
> production use case.

#### Working with hex-encoded values

Report fields like `benchmarkPrice`, `bid`, and `ask` are returned as hex strings. The reference [`HexToDecimal.daml` module](https://github.com/smartcontractkit/data-streams-canton/blob/main/examples/daml/HexToDecimal.daml) provides a `hexToUnsignedDecimal` helper for converting these to Daml `Decimal` values.

**Why `hexToUnsignedDecimal` instead of `fromHex`?**

Daml's built-in `fromHex` returns `Optional Int`, which is limited to 64 bits and returns `None` when the sign bit is set. `hexToUnsignedDecimal` uses `Decimal` to handle larger values safely.

**Decimal precision**

Daml's `Decimal` type has 38 significant digits with 10 fixed decimal places, supporting values up to approximately 10^28. EVM price values use 18 decimal places, so divide by 10^18 to get human-readable amounts:

```haskell
let oneEth : Decimal = 1000000000000000000.0
let price = v3.benchmarkPrice / oneEth  -- e.g., 3257.58 USD
```

**Signed values**

`hexToUnsignedDecimal` is unsigned. For signed two's complement values, subtract 2^n manually:

```haskell
-- Interpreting a negative int64 value
let twoTo64 : Decimal = 18446744073709551616.0
let value = hexToUnsignedDecimal negHex - twoTo64
```

The table below shows which bit widths fit within `Decimal` precision:

| Bit width | Maximum value | Fits in `Decimal`? |
| --------- | ------------- | ------------------ |
| int64     | \~1.8 × 10^19 | Yes                |
| int128    | \~3.4 × 10^38 | Yes                |
| int192    | \~6.3 × 10^57 | No                 |
| int256    | \~1.2 × 10^77 | No                 |

For values that exceed `Decimal` precision, consider storing the raw hex string and converting on-demand, or splitting the value into separate whole and fractional components.

## Important Considerations

See the [Developer Responsibilities](/data-streams/developer-responsibilities) page for important considerations when integrating Chainlink Data Streams. The following are important considerations specific to Canton integration:

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