> For the complete documentation index, see [llms.txt](https://docs.bitsafe.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/package-and-contract-operations.md).

# Package and contract operations

## Goal

Distribute a DAR to every required Canton participant, verify package parity, and deploy governance contracts through the multi-party contracts workflow.

## Audience

This guide is for Decentralization Manager operators who administer a connected set of peers. In this guide, a node is one running Decentralization Manager together with its Canton participant.

## Before you start

Confirm all of the following:

* Every operator runs a node, and each pair of nodes lists the other as a peer. See [Connect peers](/decentralization-manager/get-started/connect-peers.md).
* All nodes of the Decentralized Party run the same release. The code itself accepts any peer that has the same wire version and reports version `0.1.9` or later.
* Every peer has approved the DAR and the change window.
* You have a valid access token. You need the admin role when the node sets `DECPM_ADMIN_ROLE`. See [Authentication and operator roles](/decentralization-manager/operations-and-reference/authentication-and-operator-roles.md).
* For a contract deployment, the Decentralized Party exists. The coordinator holds the party credentials for it, and **Test Auth** succeeds.

{% hint style="warning" %}
A DAR installs executable package code on every participant that accepts it. Verify the artifact through your software supply-chain process before you distribute it. Each peer checks the SHA-256 hash of every DAR against the hash in the invitation that it accepted. Compare that hash with the published release hash before you accept.
{% endhint %}

## Choose the correct operation

| Task                                                      | Operation                                                                  | Use                                                                                                     |
| --------------------------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Upload a DAR to this node only                            | `POST /dars/upload`, or **Packages → Upload DARs**                         | Local development or diagnosis. Do not use it to reach package parity in production                     |
| Send a DAR file to this node and selected peers           | `POST /dars/distribute`, or **Packages → Distribute DARs**                 | Normal multi-party distribution                                                                         |
| Send a DAR that this node already holds to selected peers | `POST /dars/distribute-package`, or the send icon on the **Packages** page | A peer lacks a package that this node has                                                               |
| Create contracts for a Decentralized Party                | `POST /contracts`, or **Deploy Contracts** on the party page               | Multi-party preparation, signing, and execution of contract creates. This workflow does not upload DARs |

The release DARs are in the [`releases/v1/`](https://github.com/DLC-link/decentralization-manager/tree/main/releases/v1) directory of the repository.

## Distribute a DAR

### 1. Prepare the request

Set the coordinator URL, the access token, and the DAR path. `POST /dars/distribute` needs at least one peer in `peer_ids`.

```bash
export DECPM_URL="https://manager.example.com"
export DAR_PATH="./governance-core-v1-0.1.0.dar"
base64 < "$DAR_PATH" | tr -d '\n' > dar.b64
jq -n --arg f "$(basename "$DAR_PATH")" --rawfile d dar.b64 \
  '{dar_files: [{filename: $f, data: $d}],
    peer_ids: ["participant-2::1220...", "participant-3::1220..."]}' > dars.json
```

Keep the bearer token out of shell history and logs.

### 2. Start distribution

```bash
curl --fail-with-body -X POST "$DECPM_URL/dars/distribute" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d @dars.json
```

The answer is HTTP `202` with the run's `instance_name`. The coordinator sends an invitation to each selected peer. The invitation names each DAR and pins its SHA-256 hash.

### 3. Accept the invitation on every peer

In the web interface of each peer:

1. Open **Approvals**. The invitation is under **Needs your action**.
2. Click **Review ▾**. Check the coordinator, the DAR names, and each `sha256:` hash.
3. To read a DAR before you accept, click its download icon. The node fetches the DAR from the coordinator and checks it against the pinned hash.
4. Click **Accept** only when everything matches the approved change.

With the API, list the invitations and accept one by its ID:

```bash
ID=$(curl -sS "$NODE/invitations" -H "Authorization: Bearer $TOKEN" \
  | jq -r '.invitations[] | select(.invitation_type == "Dars") | .id')
curl -sS -X POST "$NODE/invitations/accept" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d "{\"id\": \"$ID\"}"
```

`GET /invitations/{id}/dars/{index}` downloads one DAR of a pending invitation. It answers HTTP `502` when the bytes do not match the pinned hash.

A peer refuses to install DAR bytes that do not match the hash it accepted. An invitation from an older coordinator can carry no hashes. The invitation then shows "no hash pinned", and the peer cannot check the content.

### 4. Monitor the workflow

Follow the run on the coordinator:

```bash
curl -sS "$DECPM_URL/workflows" -H "Authorization: Bearer $TOKEN" \
  | jq '.runs[] | select(.instance_name == "<instance_name>")
        | {status, current_step, error}'
```

The DAR workflow has three steps:

1. `WaitingForPeers`: the coordinator waits until every invited peer accepts and connects.
2. `UploadDars`: each peer downloads the DARs, checks the hashes, and uploads them through Canton's `PackageService`.
3. `Complete`: the coordinator uploads its own copy, after every peer has finished.

`GET /dars/distribute/status` reports one run of this kind only. Use `GET /workflows` to follow a specific run.

Do not start a contract deployment until the DAR run is `completed`.

### 5. Verify package parity

On the **Packages** page:

1. Click **Check Peer DARs**.
2. Add the participants to compare in the **Participants** box.
3. Turn on **Differences only**. A red cell with an error icon marks a package that a participant lacks.

With the API:

```bash
curl --fail-with-body "$DECPM_URL/packages/vetted" -H "Authorization: Bearer $TOKEN"
curl --fail-with-body "$DECPM_URL/packages/compare-peers?participants=participant-2::1220...,participant-3::1220..." \
  -H "Authorization: Bearer $TOKEN"
```

`/packages/compare-peers` reads each participant's vetted packages from the synchronizer. Leave out `participants` to compare every configured peer. A listed participant does not need to be a configured peer. Any signed-in caller can use this route.

`GET /packages/expected-versions` returns the expected version of each Splice package, from the DSO's `AmuletRules`. Other packages have no expected version.

**Expected outcome:** every required participant reports the same intended package ID before anyone creates a contract.

## Send a package that this node already holds

The send icon on the **Packages** page distributes the DAR that holds that package. The icon shows in a cell where the participant lacks the package or vets another version. The icon shows only in a web interface build with admin access. The peer's operator accepts the invitation under **Approvals**.

The API call names one package ID in the DAR:

```bash
curl --fail-with-body -X POST "$DECPM_URL/dars/distribute-package" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"package_id": "<64-hex-package-id>", "peer_ids": ["participant-2::1220..."]}'
```

The coordinator reads the DAR from its own participant and runs the same DAR workflow. The call answers HTTP `404` when no DAR on this node holds the package.

## Deploy governance contracts

The contracts workflow creates contracts through Canton's interactive submission service. It does not replace the propose, confirm, and execute lifecycle for later governed actions.

### How a deployment is pinned

The coordinator fixes the deployment before it sends any invitation:

* It resolves each package-name reference, such as `#governance-core-v1`, to the newest version with that name on the coordinator's participant. When two package IDs share the newest version, send an explicit package ID.
* It records an ordered list of creates. Each entry holds the package ID, the module, the template, and a SHA-256 commitment to the create arguments.
* It also records the party's current threshold.

Each peer sees this list under **Approved creates** in the invitation. Before it signs, each peer checks every prepared transaction:

* The transaction holds exactly one create, as its root node.
* The template and the argument commitment match the approved create.
* The transaction acts as the Decentralized Party only.
* The prepared hash matches the transaction.

A peer refuses an exercise, an extra node, or a substituted template or argument. The package IDs stay pinned through preparation and every retry, even if someone uploads another version.

The argument commitment is not a hash of the JSON request. It hashes the Daml value after Decentralization Manager normalizes it, so compare the values that the invitation shows.

If the party's threshold changes after the run starts, the run stops before preparation. Start a new run, so that the peers confirm the new threshold.

An invitation that a peer accepted before this check existed carries no commitments. An upgraded peer refuses to sign it. Restart that deployment from an upgraded coordinator. Upgrade every node before a deployment.

### 1. Confirm prerequisites

* Verify package parity on every participant.
* Confirm the template and its field order against the exact DAR version.
* Confirm the Decentralized Party, the participant IDs, the member parties, and the operator party.
* List at least as many member parties as the party's threshold. List them in the same order as `participant_ids`.
* Confirm that the coordinator has no other run in progress for this party, as coordinator or as peer.
* Record the intended package ID and template in the change record.

### 2. Start from the web interface

For a party without a `GovernanceRules` contract:

1. Open **Parties** and click the party.
2. Click **Deploy Contracts**.
3. Click the **Governance Core** card. The card stays disabled until the governance-core DAR is on this node.
4. Enter the contract fields, review the participants and the operator party, and start the run.

### 3. Start through the API

This example deploys one `GovernanceRules` contract. Replace every placeholder with values from the target environment.

```bash
curl --fail-with-body -X POST "$DECPM_URL/contracts" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "decentralized_party_id": "governed-app::1220...",
    "participant_ids": [
      "participant-1::1220...",
      "participant-2::1220...",
      "participant-3::1220..."
    ],
    "participant_parties": [
      "member-1::1220...",
      "member-2::1220...",
      "member-3::1220..."
    ],
    "operator_party": "operator::1220...",
    "contracts": [
      {
        "id": "governance-rules",
        "name": "GovernanceRules",
        "package_id": "#governance-core-v1",
        "module_name": "Governance.Rules",
        "entity_name": "GovernanceRules",
        "fields": [
          { "type": "decentralized_party" },
          {
            "type": "party_set",
            "parties": [
              "member-1::1220...",
              "member-2::1220...",
              "member-3::1220..."
            ]
          },
          { "type": "governance_threshold" },
          { "type": "rel_time", "microseconds": 1800000000 },
          { "type": "none" }
        ]
      }
    ]
  }'
```

`GovernanceRules` takes five fields, in template order. `governance_threshold` with no value uses the party's own threshold. To set another value, send `{ "type": "int64", "value": <n> }`. Use `party_set` for a Daml `Set Party`. Do not use `attestors_set` for it. The request has no `dar_files` field.

The answer is HTTP `202` with the run's `instance_name`. A second start for the same party gets HTTP `409`.

### 4. Accept the contracts invitation

On every invited peer, open **Approvals** and click **Review ▾**. Compare each entry under **Approved creates** with your deployment configuration: `module:template`, **Package**, and **Arguments SHA-256**. Accept only when every entry matches.

### 5. Monitor the deployment

Follow the run with `GET /workflows`, as in step 4 of [Distribute a DAR](#distribute-a-dar). The contracts workflow has five steps:

1. `WaitingForPeers`: the coordinator waits for every invited peer.
2. `PrepareSubmissions`: the coordinator prepares one interactive submission for each contract.
3. `SignSubmissions`: the coordinator and each peer check each prepared transaction. Each node then signs its hash with its own Daml key.
4. `ExecuteSubmissions`: the coordinator executes the signed submissions on Canton.
5. `Complete`: the run ends.

### 6. Verify the result

Query the governance state of the Decentralized Party:

```bash
curl --fail-with-body \
  "$DECPM_URL/governance/state?party_id=governed-app::1220..." \
  -H "Authorization: Bearer $TOKEN"
```

You can also query the created template directly:

```bash
curl --fail-with-body \
  "$DECPM_URL/contracts/query?party_id=governed-app::1220...&package_id=%23governance-core-v1&module_name=Governance.Rules&entity_name=GovernanceRules&interface=false" \
  -H "Authorization: Bearer $TOKEN"
```

Record the run's `instance_name`, the package ID, the created contract ID, the participants, the template, and the completion time.

**Expected outcome:** the contract is active and visible to the intended parties, and every required participant keeps package parity.

## Concurrent runs

A node can coordinate several runs at a time. Each response carries the run's `instance_name`, so you can follow and address one run.

A node refuses to start a kick, add-party, change-threshold, or contracts run for a party that already has a run in progress on that node. The node counts its runs in either role, as coordinator or as peer. The refusal is HTTP `409` with "already has a … workflow in flight". Runs for different parties can run at the same time. DAR runs are not tied to a party.

The guard is local to each node. Decentralization Manager does not stop two different nodes from coordinating conflicting runs on the same party.

## Failure handling

### A peer does not receive an invitation

* Confirm that both nodes list each other as peers, and that the Noise port is reachable.
* Confirm that the peer runs the same release.
* Confirm that the peer's public address and Noise key have not changed.
* Do not bypass the peer with a local-only upload for a production deployment.

### A DAR upload succeeds on some nodes and fails on others

Stop before contract creation. A DAR upload is a local Canton operation, so a failed run can leave partial package state.

1. Read the run's `error` with `GET /workflows`.
2. Compare the participants with **Check Peer DARs** or `GET /packages/compare-peers`.
3. Resolve the failing node's Canton Admin API, storage, or package error.
4. Click **Retry** on the coordinator's run card, or call `POST /workflows/{instance_name}/retry`. A retry resumes at the step that failed.
5. Compare all participants again.

You can also send a missing package to one peer with the send icon or `POST /dars/distribute-package`.

### Contract preparation or execution fails

Do not start the same deployment again right away.

1. Read the run's `current_step` and `error` with `GET /workflows`.
2. Query the target template to find out whether the contract already exists.
3. Capture sanitized coordinator and peer logs.
4. Click **Retry** on the coordinator's run card after you fix the cause. The retry keeps the pinned package IDs and commitments.
5. Start a new run if the party's threshold changed, or if the commitments must change.

You can retry only a failed coordinator run. A peer's run returns to in progress when its coordinator retries.

### The coordinator restarts or becomes unavailable

The coordinator drives each run. After a restart, it resumes each in-progress run at the step that it recorded. Peers resume their runs too.

A coordinator that hears nothing from a peer for 10 minutes treats that peer as gone. A peer that gives up on a run tells the coordinator. The run fails, and names the peers, when the remaining peers cannot finish it.

Restore the coordinator, inspect the run and the Canton state, and then retry the failed run.

### A peer declines the workflow

Treat the workflow as not approved. Resolve the change with that operator. Do not start a new run until the peer has approved the artifact and the contract definition.

## Upgrade and migration boundary

A new DAR does not migrate active contracts. Daml package versions can coexist, and existing proposals stay bound to the package version that created them.

Before you deploy a replacement version:

1. Identify the active contracts and in-flight proposals on the old package.
2. Decide whether to drain, cancel, or migrate them.
3. Verify compatibility with the current Decentralization Manager and Canton versions.
4. Publish a separate migration and rollback plan.
5. Distribute and verify the new DAR before you create replacement contracts.

Do not change the meaning of an existing template version.

## Operational record

For each run, keep:

* The approved source and an immutable artifact reference.
* The DAR SHA-256 hash from the invitation.
* The Decentralization Manager version or commit.
* The Canton version.
* The coordinator and participant IDs.
* The DAR filename and package ID.
* The run's `instance_name` and terminal state.
* The contract package, module, template, and contract ID.
* Sanitized error records and remediation notes.

Do not store access tokens, client secrets, Noise private keys, or database encryption keys in the change record.

## Technical sources

* [DAR workflow steps](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/dars/mod.rs)
* [Contracts workflow steps](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/contracts/mod.rs)
* [Package resolution and deployment commitments](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/contracts/steps/prepare.rs)
* [Peer checks before signing](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/contracts/steps/sign.rs)
* [Peer checks of accepted invitations](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/validation.rs)
* [Workflow handlers](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/handlers/workflows.rs)
* [Invitation handlers](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/handlers/invitations.rs)
* [Package comparison handlers](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/handlers/parties.rs)
* [API request types](https://github.com/DLC-link/decentralization-manager/blob/main/crates/common/src/api.rs)
* [Custom Daml template guide](https://github.com/DLC-link/decentralization-manager/blob/main/docs/CUSTOM_DAML_TEMPLATES.md)

## Next actions

* Use [Governance lifecycle](/decentralization-manager/concepts-and-development/governance-lifecycle.md) to propose, confirm, and execute the first governed action.
* Use [Backup, recovery, and upgrades](/decentralization-manager/operations-and-reference/backup-recovery-and-upgrades.md) when an operation does not reach a terminal state.
* Review [Compatibility, releases, and troubleshooting](/decentralization-manager/operations-and-reference/compatibility-releases-and-troubleshooting.md), and plan the migration before you replace active contract packages.

## Related pages

* [Governance lifecycle](/decentralization-manager/concepts-and-development/governance-lifecycle.md)
* [Module selection and custom Daml](/decentralization-manager/concepts-and-development/module-selection-and-custom-daml.md)
* [Add a member to a Decentralized Party](/decentralization-manager/operations-and-reference/add-a-member.md)
* [API and workflow reference](/decentralization-manager/operations-and-reference/api-and-workflow-reference.md)
* [Authentication and operator roles](/decentralization-manager/operations-and-reference/authentication-and-operator-roles.md)

## Next step

👉 **Exercise the deployed contracts:** [Governance lifecycle](/decentralization-manager/concepts-and-development/governance-lifecycle.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/package-and-contract-operations.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
