> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirador.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Canton Transactions

> Correlate Canton (Daml Ledger API) transactions with a trace via web3.canton.addTxHint

## Overview

Mirador correlates Canton (Daml Ledger API v2) transactions to a trace by ledger **`updateId`** — the unique identifier of an on-ledger update, returned when you submit a command to a participant. The Web3Plugin exposes this under its `web3.canton` namespace.

```typescript theme={null}
trace.web3.canton.addTxHint(updateId);
```

Like Solana, Canton hints take no chain argument. The chain identity is implicit — Canton lives outside the EVM `Chain` enum, and the hint is emitted on the wire as `chain_name = "canton"`. On the platform side, the canton-hint processor resolves the full transaction server-side from the `updateId` and emits its events into the trace waterfall, alongside any other on-chain or off-chain activity.

<Note>
  Canton methods require the `Web3Plugin`. See [Plugins](/concepts/plugins) for setup.
</Note>

## Adding a Canton Transaction Hint

Pass the `updateId` your participant's Ledger API returns after a successful command — e.g. `submit-and-wait-for-transaction` on the JSON Ledger API, or `CommandService.SubmitAndWaitForTransaction` over gRPC. Use whatever Canton client you already have; the SDK only needs the resulting id.

```typescript theme={null}
// `submit` is your own participant client (JSON Ledger API, gRPC, @daml/ledger, …)
const { updateId } = await submit(createOrExerciseCommand);
trace.web3.canton.addTxHint(updateId);
```

### Scoping to a Party

`partyId` is optional. Include it to scope the update to a specific party, or omit it when the participant only co-hosts the contract as an **observer** — the backend can resolve the update from the `updateId` alone.

```typescript theme={null}
trace.web3.canton.addTxHint(updateId, 'Alice::1220...');  // scope to a party
trace.web3.canton.addTxHint(updateId);                     // observer co-host — no party
```

### With Details

Attach a free-form note for downstream debugging:

```typescript theme={null}
trace.web3.canton.addTxHint(updateId, 'Alice::1220...', 'IOU transfer');
```

### Method Signature

```typescript theme={null}
trace.web3.canton.addTxHint(updateId: string, partyId?: string, details?: string): Trace
```

| Parameter  | Type     | Required | Description                                                   |
| ---------- | -------- | -------- | ------------------------------------------------------------- |
| `updateId` | `string` | Yes      | Canton ledger update id (the transaction's unique identifier) |
| `partyId`  | `string` | No       | Party to scope the update to; omit for observer co-hosts      |
| `details`  | `string` | No       | Free-form note attached to the hint for debugging context     |

## End-to-End Example

```typescript theme={null}
import { Client, Web3Plugin } from '@miradorlabs/nodejs-sdk';

const client = new Client('your-api-key', { plugins: [Web3Plugin()] });

async function transferIou(params: TransferParams) {
  const trace = client.trace({ name: 'CantonTransfer' })
    .addAttributes({
      party: params.owner,
      templateId: params.templateId,
      contractId: params.contractId,
    })
    .addTags(['canton', 'iou']);

  try {
    // Exercise the Transfer choice via your participant's Ledger API.
    const { updateId } = await ledger.exercise(params.contractId, 'Transfer', {
      newOwner: params.recipient,
    });

    trace.web3.canton.addTxHint(updateId, params.owner, 'IOU transfer');
    trace.addEvent('confirmed');
  } catch (err) {
    trace.error('transfer_failed', { message: (err as Error).message });
  }
}
```

<Tip>
  For a complete, runnable example — submitting Canton commands and tracing them
  end-to-end — see the
  [`canton-example`](https://github.com/miradorlabs/canton-example) repo.
</Tip>

## Why No Chain Argument?

EVM tx hints carry a numeric chain ID so the backend knows which chain to resolve the tx hash on. Canton has no such enum — a Canton network is a set of synchronizers reached through a participant node, not an id-keyed chain. So the API omits the chain parameter and emits `chain_name = "canton"` on the wire:

```typescript theme={null}
// EVM — chain is required
trace.web3.evm.addTxHint('0x123...', 'ethereum');

// Canton — no chain; the updateId is the identifier
trace.web3.canton.addTxHint('1220...');
```

## Observer Co-Hosts

Canton's privacy model means a participant only sees updates for the parties it hosts. If your trace runs on a participant that co-hosts a contract as an **observer** — rather than acting as a signatory — you may not have a party to act as. Pass just the `updateId` and omit `partyId`; the backend resolves the update from the id alone.

```typescript theme={null}
trace.web3.canton.addTxHint(updateId); // observer — no party needed
```

## Best Practices

### Add the Hint as Soon as You Have the updateId

Record it the moment the submission returns — Canton assigns the `updateId` on commit, so there's nothing to wait for.

### Label Each Step in a Multi-Command Flow

When one user action produces several commands (e.g. mint then transfer), use the optional `details` arg to label each leg so the waterfall is self-explanatory:

```typescript theme={null}
trace.web3.canton.addTxHint(mintUpdateId, owner, 'Mint');
trace.web3.canton.addTxHint(xferUpdateId, owner, 'Transfer');
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Solana Transactions" icon="wave-pulse" href="/concepts/solana-transactions">
    The other chain-implicit hint
  </Card>

  <Card title="EVM Transaction Hints" icon="cube" href="/concepts/transaction-hints">
    EVM tx correlation and the supported chain list
  </Card>

  <Card title="Plugins" icon="puzzle-piece" href="/concepts/plugins">
    Web3Plugin setup and namespaces
  </Card>
</CardGroup>
