Skip to content

rmourey26/c7-ledger-rust-wrapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 

Repository files navigation

Canton Ledger API Client (Rust)

A strongly-typed, asynchronous Rust wrapper for the Canton v2 HTTP JSON API.

This library is a Rust port of the TypeScript c7_ledger repository. It enables Rust applications to interact with Daml/Canton ledgers to submit commands, query the active contract set (ACS), and manage ledger state.

Features

  • Async/Await: Built on tokio and reqwest for non-blocking I/O.
  • Strong Typing: Uses Rust enums to strictly define Create vs Exercise commands.
  • JSON Serialization: Seamless integration with serde_json for dynamic Daml template arguments.
  • Error Handling: Implements anyhow for clean error propagation.

Project Structure

Ensure your file tree looks like this:

.
├── Cargo.toml          # Dependencies
├── README.md           # This file
└── src
    ├── client.rs       # HTTP Client logic and API endpoints
    ├── lib.rs          # Module exports
    ├── main.rs         # Example workflow (IOU)
    └── models.rs       # Structs for Commands, Responses, and Ledger State

Installation

Add the following dependencies to your Cargo.toml:

[dependencies]
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"

Usage

1. Initialize the Client

use crate::client::CantonClient;

// Initialize with the Ledger API URL and a signed JWT
let client = CantonClient::new("http://localhost:7575", "YOUR_JWT_TOKEN");

2. Create a Contract

Submit a CreateCommand to the ledger. This function blocks asynchronously until the transaction is committed (Submit and Wait).

use serde_json::json;

let create_args = json!({
    "owner": "Alice",
    "amount": 100
});

let response = client.create(
    "Main:Iou",          // Template ID
    create_args,         // Arguments
    vec!["Alice".to_string()] // Act As
).await?;

println!("Contract Created. Update ID: {}", response.update_id);

3. Query Active Contracts

Fetch contracts currently active on the ledger, filtering by Template ID.

let contracts = client.list_active_contracts(
    vec!["Main:Iou".to_string()], // Filter by Template ID
    None                          // Optional query filter
).await?;

for contract in contracts {
    println!("Found contract: {}", contract.contract_id);
}

4. Exercise a Choice

Exercise a choice on a specific contract ID.

let exercise_args = json!({
    "newOwner": "Bob"
});

client.exercise(
    "00xx...contract_id...", // Contract ID
    "Main:Iou",              // Template ID
    "Transfer",              // Choice Name
    exercise_args,           // Choice Arguments
    vec!["Alice".to_string()] // Act As
).await?;

Prerequisites for Running the Example

To run the default main.rs workflow, you need a running Canton/Daml ledger with the following setup:

  1. Daml Model: A template named Main:Iou must be deployed.
  2. Parties: Parties named "Alice" and "Bob" must be allocated.
  3. Auth: You must generate a JWT token for the ledger that has actAs permissions for "Alice".

Running the Project

cargo run

Implementation Details

Models (src/models.rs)

The library separates the command payload (CommandPayload) from the specific command types (CreateCommand, ExerciseCommand). This ensures that you cannot send a command missing required fields (like sending a Create command without create_arguments).

Client (src/client.rs)

The client handles HTTP status validation automatically. If the Ledger API returns a non-200 status code, the client will return an Err containing the API error message.

License

MIT

About

Canton c7 ledger rust wrapper

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages