> 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/cbtc-1/guides/transfer-and-receive-cbtc.md).

# Transfer and receive CBTC

[CBTC overview](/cbtc-1/overview.md) · [CBTC environments and prerequisites](/cbtc-1/get-started/environments-and-prerequisites.md) · [Transfer and receive CBTC](/cbtc-1/guides/transfer-and-receive-cbtc.md)

### Outcome

Distribute CBTC to multiple Canton parties, record one result for each sender-side transfer, and manage CBTC holdings without creating an unsafe retry or consolidation workflow.

### Terminology

This guide uses **UTXO** as shorthand used by the current library for an active CBTC holding contract. A CBTC holding on Canton Network is not a Bitcoin UTXO.

### Before you start

* Complete one sender-to-receiver transfer and receiver acceptance in the intended environment.
* Use an Engineering-approved `cbtc-lib`, `canton-lib`, DAR, and Canton compatibility row.
* Confirm authentication, the sender party, the CBTC instrument identifier, the registry service, and the intended environment.
* Query the sender’s current holdings and outgoing offers.
* Confirm the sender has enough available CBTC for the full distribution.
* Define a durable application-side row identifier and reconciliation record for every recipient.
* Stop other processes from spending or restructuring the same sender’s holdings during the run.

{% hint style="info" %}
A batch is not one atomic transfer. In `v0.6.4`, the library submits sender-side transfers sequentially. Each successful submission creates a transfer instruction or offer that the receiver must still accept unless a separately supported preapproval flow applies.
{% endhint %}

### Choose the batch interface

| Interface                        | Use                                                                               | Result handling                                                                                                                                                                                   |
| -------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cbtc::batch::submit_from_csv()` | Read `receiver,amount` rows from a CSV file and submit a sequential distribution. | The helper returns an overall `Result<(), String>`. It does not return the per-item result collection to the caller. Use it only when its logging behavior meets the approved operational policy. |
| `cbtc::distribute::submit()`     | Submit an in-memory recipient list.                                               | Returns successful and failed counts plus one result per row. It can call an asynchronous callback after each row completes.                                                                      |

For production-style reconciliation, prefer the interface that exposes per-item results and a durable callback.

### How the current sequential flow works

At `v0.6.4`, the distribution flow:

1. Authenticates and refreshes the access token when required.
2. Queries all active sender holdings once at the start.
3. Uses those holding contract identifiers as the first transfer’s inputs.
4. Fetches transfer-factory context once and reuses it for the run.
5. Submits one transfer at a time.
6. Uses the sender change holdings returned by a successful row as the next row’s inputs.
7. Records success or failure for each row and then attempts the next row.

This is a sequential chained flow. It is not concurrent, and it does not pre-split holdings.

### 1. Prepare and validate recipient input

The repository example accepts this CSV shape:

```
receiver,amount
receiver1-party::1220...,5.0
receiver2-party::1220...,3.5
```

Before passing data to the library:

* Reject empty receiver identifiers.
* Validate every receiver against the intended environment.
* Parse every amount as the supported decimal type.
* Reject zero, negative, or amounts outside the documented policy limits.
* Reject duplicate application-side row identifiers.
* Review repeated receiver identifiers intentionally. Do not assume one receiver appears only once.
* Sum all amounts and compare the total with the sender’s available balance.

The CSV helper rejects malformed amounts and an empty recipient list. The reviewed source does not implement business-reference deduplication or complete recipient-policy validation. Perform those checks in the calling application.

### 2. Create a run record

Create a durable run record before submission. Store:

* Application run identifier.
* Application row identifier.
* Row index.
* Receiver.
* Amount.
* Intended environment.
* Submission state.
* Transfer-offer contract identifier when available.
* Canton update identifier when available.
* Library reference when available.
* Error and raw-response location, with secrets removed.

#### Reference limitation in `v0.6.4`

The optional `reference_base` generates a reference from the base value, sender, and receiver. It does not include the row index or amount. Repeated rows for the same receiver can therefore produce the same generated reference.

Do not treat this generated value as a guaranteed per-row idempotency key. Keep a separate application-side row identifier and reconcile state before replay.

### 3. Check holdings and pending work

Immediately before submission:

1. Query active CBTC holdings for the sender.
2. Record the holding contract identifiers and total available amount.
3. Query pending outgoing offers and unresolved withdrawals.
4. Confirm no other batch, split, consolidation, redemption, or transfer process can consume the same holdings.
5. Apply the holding-count and transaction-size limits documented for the supported release.

The batch implementation fetches holdings once. Concurrent mutations can make its chained input set stale.

### 4. Run a batch

The simple repository example uses:

```bash
RECIPIENTS_CSV=recipients.csv cargo run --example batch_distribute
```

The callback example uses:

```bash
CSV_PATH=recipients.csv cargo run --example batch_with_callback
```

Use placeholders for credentials and environment values. Never commit `.env` files, access tokens, passwords, or production party identifiers.

### 5. Record each callback result

The callback receives one result after each sender-side submission attempt.

| Field                | Use                                                                                            |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| `success`            | Whether the library classified the sender-side submission and response parsing as successful.  |
| `transfer_index`     | Zero-based position in the submitted recipient list.                                           |
| `receiver`, `amount` | Match the result to the intended row. Also verify the application-side row identifier.         |
| `transfer_offer_cid` | Track the created transfer instruction or offer.                                               |
| `update_id`          | Correlate the result with the Canton update.                                                   |
| `reference`          | Store as supporting metadata. Do not assume uniqueness under the limitation above.             |
| `raw_response`       | Retain securely for diagnostics when policy permits. Remove secrets before support escalation. |
| `error`              | Classify the row as failed or ambiguous and apply the approved recovery procedure.             |

Make the callback durable and safe to call once per completed attempt. If writing to a database, protect the application row from duplicate callback processing.

### 6. Reconcile the run

Classify each row separately:

* **Submitted:** The callback includes a transfer-offer contract identifier and Canton update identifier. This confirms sender-side submission, not receiver acceptance.
* **Accepted:** The receiver accepted the intended offer, and both parties’ holdings reflect the completed transfer.
* **Failed before submission:** Evidence proves that no ledger update committed.
* **Ambiguous:** The request may have committed, but the client lacks a parseable or authoritative result.
* **Rejected, cancelled, or expired:** The offer reached the corresponding terminal state. Use the versioned reference for exact state names and expiry policy.

After the sender-side run, verify incoming offers with each receiver or the approved receiving service. Do not mark a distribution complete from `successful_count` alone.

### Partial failure and safe resume

The reviewed implementation continues to later rows after a failed submission or response-parsing error. It preserves the last known input-holding list in memory.

For production recovery:

1. Stop the run when an outcome is ambiguous.
2. Requery active holdings and outgoing offers from authoritative sources.
3. Match receiver, amount, application row identifier, offer identifier, update identifier, and available reference metadata.
4. Mark already-created offers as submitted. Do not create replacements for them.
5. Resume only rows proven not to have committed.
6. Build a new run from fresh holdings. Do not reuse a stale in-memory holding list.
7. Keep accepted, pending, failed, and ambiguous rows in separate states.

Never rerun the complete CSV after partial success.

### Concurrency policy

`cbtc-lib` `v0.6.4` processes one distribution sequentially. Do not run parallel distributions, transfers, redemptions, splits, or consolidations from the same sender without an application-level lock and fresh-state strategy.

Use the supported release limits for recipient count, total amount, execution duration, timeouts, and rate limits.

### Manage CBTC holdings

#### Inspect holdings

Use the active-contract query or the consolidation count helper to record:

* Holding count.
* Holding contract identifiers.
* Total amount.
* Pending operations that reference those holdings.
* Last successful reconciliation time.

A high holding count can increase transaction size and operational complexity. Use the current operational limits when deciding whether to consolidate.

#### Consolidate holdings

The `v0.6.4` consolidation function performs a self-transfer with merge-split metadata. It can consolidate all active holdings or a selected set. If the party has fewer holdings than the supplied threshold, `check_and_consolidate()` does nothing. If the threshold is met or exceeded, it consolidates all queried holdings and returns the resulting holding contract identifiers.

The repository example uses a configurable threshold and defaults that example to `10`. Treat this as example behavior, not a production limit. Use the threshold documented for the target environment.

Run the example only after review:

```bash
CONSOLIDATION_THRESHOLD=<approved-threshold> cargo run --example consolidate_utxos
```

Before consolidation:

* Reconcile pending transfers and withdrawals.
* Confirm the selected holdings are still active.
* Stop concurrent operations for the party.
* Estimate the expected resulting holding count and transaction impact.
* Record the input holding identifiers.

After consolidation, query the party again and verify the total amount and returned holding identifiers.

#### Split holdings

The `v0.6.4` split function uses sequential self-transfers. It separates each requested amount in order, then feeds the returned change holdings into the next split. It returns output holding identifiers and remaining change identifiers.

Use split only when an approved downstream workflow requires specific holding sizes. Confirm:

* The requested amounts and order.
* The selected input holdings.
* The expected remaining change.
* Behavior when requested amounts consume the exact available total.
* The release-specific recovery procedure if a later split step fails.

Do not split solely to prepare the sequential batch flow. The current batch implementation is designed to chain change holdings without pre-splitting.

### Expected result

A completed operation has:

* One durable record per recipient.
* A reconciled sender-side result for every row.
* Receiver acceptance or another approved terminal state for every created offer.
* No ambiguous row left queued for automatic retry.
* A final sender balance and holding set that match the reconciled run.
* A recorded before-and-after holding set for every split or consolidation.

### Troubleshooting

<table data-search="false"><thead><tr><th>Symptom</th><th>Check</th><th>Safe next action</th></tr></thead><tbody><tr><td>No recipients found</td><td>CSV path, header, and parsed row count</td><td>Correct the file. Do not submit an unreviewed replacement.</td></tr><tr><td>Invalid amount</td><td>Decimal syntax and business amount rules</td><td>Reject the row before any submission.</td></tr><tr><td>No holdings available</td><td>Sender party, environment, active holdings, and pending operations</td><td>Stop and reconcile the sender. Do not retry with another party implicitly.</td></tr><tr><td>Some rows succeed and later rows fail</td><td>Per-item results, current holdings, token refresh, and errors</td><td>Do not rerun the complete CSV. Requery authoritative state and resume only proven-uncommitted rows.</td></tr><tr><td>Ledger response exists but parsing fails</td><td>Raw response, update visibility, outgoing offers, and client compatibility</td><td>Treat the row as ambiguous. Reconcile before any retry.</td></tr><tr><td>Sender-side success but receiver balance is unchanged</td><td>Incoming offer, receiver acceptance, preapproval policy, rejection, cancellation, and expiry</td><td>Complete or resolve the receiver-side flow. Do not duplicate the sender submission.</td></tr><tr><td>Generated references repeat</td><td>Repeated receiver identifiers and shared <code>reference_base</code></td><td>Use application-side row identifiers. Escalate before relying on the library reference for replay protection.</td></tr><tr><td>Consolidation returns an unexpected holding set</td><td>Input holdings, concurrent operations, transaction response, and final active holdings</td><td>Stop new operations and reconcile total amount and contract identifiers.</td></tr><tr><td>Split stops after creating earlier outputs</td><td>Completed split steps, current change holdings, and remaining requested amounts</td><td>Requery holdings. Do not restart from the original input identifiers.</td></tr></tbody></table>

### Technical sources

* [`cbtc-lib` README at `v0.6.4`](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/README.md)
* [CSV batch helper](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/src/batch.rs)
* [Sequential distribution flow](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/src/distribute.rs)
* [Sequential chained transfer and result model](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/src/transfer.rs)
* [Batch CSV example](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/examples/batch_distribute.rs)
* [Callback example](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/examples/batch_with_callback.rs)
* [Consolidation implementation](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/src/consolidate.rs)
* [Consolidation example](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/examples/consolidate_utxos.rs)
* [Split implementation](https://github.com/DLC-link/cbtc-lib/blob/v0.6.4/src/split.rs)

### Related pages

* [Transfer and receive CBTC](/cbtc-1/guides/transfer-and-receive-cbtc.md)
* [CBTC authentication](/cbtc-1/get-started/authentication.md)
* [CBTC errors, retries, and troubleshooting](/cbtc-1/concepts-and-reference/errors-retries-and-troubleshooting.md)
* [CBTC compatibility and release notes](/cbtc-1/concepts-and-reference/compatibility-and-release-notes.md)
* [CBTC SDK, API, and integration reference](/cbtc-1/concepts-and-reference/sdk-api-and-integration-reference.md)

### Next step

👉 **Plan safe recovery:** [CBTC errors, retries, and troubleshooting](/cbtc-1/concepts-and-reference/errors-retries-and-troubleshooting.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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.bitsafe.finance/cbtc-1/guides/transfer-and-receive-cbtc.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
