A comprehensive Go SDK for interacting with DAML ledgers, featuring a complete client library, service abstractions, and a powerful code generator for generating type-safe Go code from DAML (.dar) files.
The Go DAML SDK provides a comprehensive toolkit for building Go applications that interact with DAML ledgers. It follows a modular architecture separating concerns between client interaction, service abstraction, and code generation. The SDK includes a full-featured gRPC client for ledger operations, high-level service abstractions for common patterns, and an integrated code generator that creates type-safe Go code from DAML definitions.
The public SDK components are located under pkg/, which includes the client, service, model, auth, codec, errors, and
types packages intended for direct use by application developers. The internal/codegen/ directory contains the code
generator implementation, which parses DAML-LF (DAML Language Format) binaries extracted from .dar archives and
generates corresponding Go structs with proper JSON serialization logic.
- Complete DAML Client Library - Full gRPC client for DAML Ledger API with connection management, authentication, and TLS support
- Dual-Connection Support - Separate connections for ledger and admin endpoints with automatic service routing
- Service Layer Abstractions - High-level services for common ledger and administrative operations
- Ledger Services - Command submission, command completion, event querying, state management, update service, package service, version service, interactive submission
- Admin Services - Package management, user management, party management, participant pruning, command inspection, identity provider configuration
- Topology Services - Topology manager read/write operations for namespace delegations, party-to-key mappings, and party-to-participant mappings
- Authentication Support - Bearer token authentication with automatic token injection via gRPC interceptors
- Error Handling - Comprehensive DAML-specific error processing with categorized error types (authorization, validation, ledger-specific, connection errors)
- JSON Codec - Custom JSON serialization/deserialization for complex DAML types including Records, Variants, Enums, and primitive types
- Type-safe Go code generation from DAML definitions with proper type mapping
- Custom JSON serialization for complex DAML types (Records, Variants, Enums)
- PackageID extraction and embedding in generated code
- Multi-version DAML-LF support - Supports both DAML-LF v2 and v3 with automatic version detection
- Cross-platform support (Linux, macOS, Windows - amd64 and arm64)
- Clean CLI interface with comprehensive error handling and debug logging
- Template-based generation using Go's text/template engine for flexible code generation
# Clone the repository
git clone https://github.com/smartcontractkit/go-daml.git
cd go-daml
# Build the CLI tool
make build
# The binary will be available at ./bin/godamlmake install
# Binary will be installed to $GOPATH/bin/godamlgo get github.com/smartcontractkit/go-damlimport (
"context"
"github.com/smartcontractkit/go-daml/pkg/client"
"github.com/rs/zerolog/log"
)
bearerToken := "your-auth-token"
grpcAddress := "localhost:6865"
adminAddress := "localhost:6866"
tlsConfig := client.TlsConfig{}
cl, err := client.NewDamlClient(bearerToken, grpcAddress).
WithAdminAddress(adminAddress).
WithTLSConfig(tlsConfig).
Build(context.Background())
if err != nil {
log.Fatal().Err(err).Msg("failed to build DAML client")
}
cl.CommandService.SubmitAndWait(ctx, commands)
cl.EventQueryService.GetActiveContracts(ctx, filter)
cl.StateService.GetLedgerEnd(ctx)
cl.UserMng.CreateUser(ctx, userRequest)
cl.PartyMng.AllocateParty(ctx, partyRequest)
cl.TopologyManagerWrite.GenerateTransactions(ctx, request)# Generate Go code from a DAR file
./bin/godaml --dar ./contracts.dar --output ./generated --go_package contracts
# With debug logging
./bin/godaml --dar ./contracts.dar --output ./generated --go_package main --debug| Parameter | Required | Description |
|---|---|---|
--dar |
âś… | Path to the DAR file |
--output |
âś… | Output directory where generated Go files will be saved |
--go_package |
âś… | Go package name for generated code |
--debug |
❌ | Enable debug logging (default: false) |
./bin/godaml --help- Go 1.24.1 or later
- Make
# Build for current platform
make build
# Build for all platforms
make build-all
# Run tests
make test
# Run tests with coverage
make test-coverage
# Format code
make fmt
# Lint code (requires golangci-lint)
make lint
# Development workflow
make dev
# Release workflow
make release
# Show all available commands
make help# Run all tests
make test
# Run tests with coverage report
make test-coverage
# Run specific test
go test ./internal/codegen -v -run TestGetMainDalfThe Go DAML SDK is organized into the following modules:
-
pkg/client/: DAML ledger gRPC client implementation- Builder pattern for flexible client configuration
- Connection management with TLS support
- Authentication via Bearer tokens with automatic injection
- Service factory exposing all ledger and admin services
- gRPC interceptors for authentication and error handling
-
pkg/service/ledger/: Ledger operations- Command Service: Submit commands synchronously
- Command Completion: Track command completion status
- Command Submission: Asynchronous command submission
- Event Query Service: Query active contracts, transaction trees, flat transactions
- Interactive Submission: Multi-step command submission workflows
- State Service: Query ledger state and configuration
- Update Service: Subscribe to ledger updates
- Package Service: Query and manage DAML packages
- Version Service: Get ledger API version information
-
pkg/service/admin/: Administrative operations- Package Management: Upload and validate DAR packages
- User Management: Create, update, list, and delete users with rights management
- Party Management: Allocate and manage parties
- Participant Pruning: Prune ledger history
- Command Inspection: Inspect command status
- Identity Provider Configuration: Configure identity providers
-
pkg/service/topology/: Topology management operations- Topology Manager Write: Generate, authorize, sign, and add topology transactions
- Topology Manager Read: Query namespace delegations, party-to-key mappings, party-to-participant mappings
- External Party Support: Onboarding transactions for external party allocation
-
pkg/service/testing/: Testing utilities- Time Service: Control ledger time for testing
-
pkg/model/: Common data models and type definitions for ledger and admin operations -
pkg/auth/: Authentication mechanisms (Bearer token interceptor) -
pkg/codec/: JSON codec for DAML types with custom marshaling/unmarshaling -
pkg/errors/: DAML-specific error handling with categorized error types -
pkg/types/: DAML type system definitions
codegen.go: DAR file processing, orchestration, and AST generationastgen/factory.go: AST generator factory with automatic DAML-LF version detectionastgen/v2/: DAML-LF v2 AST generation implementationastgen/v3/: DAML-LF v3 AST generation implementationmodel/manifest.go: DAR manifest parsing and metadata extractionmodel/template.go: Template data structures for code generationtemplate.go: Go template processing, binding, and file generationtemplate_test.go: Template generation tests
cmd/main.go: Command-line interface for code generation
examples/admin_app/: Administrative operations examplesexamples/ledger_app/: Ledger interaction examples
package main
import (
"context"
"os"
"github.com/smartcontractkit/go-daml/pkg/client"
"github.com/rs/zerolog/log"
)
func main() {
grpcAddress := os.Getenv("GRPC_ADDRESS")
if grpcAddress == "" {
grpcAddress = "localhost:8080"
}
bearerToken := os.Getenv("BEARER_TOKEN")
if bearerToken == "" {
log.Warn().Msg("BEARER_TOKEN environment variable not set")
}
tlsConfig := client.TlsConfig{}
cl, err := client.NewDamlClient(bearerToken, grpcAddress).
WithTLSConfig(tlsConfig).
Build(context.Background())
if err != nil {
log.Fatal().Err(err).Msg("failed to build DAML client")
}
ctx := context.Background()
version, err := cl.VersionService.GetLedgerApiVersion(ctx)
if err != nil {
log.Error().Err(err).Msg("failed to get ledger version")
}
ledgerEnd, err := cl.StateService.GetLedgerEnd(ctx)
if err != nil {
log.Error().Err(err).Msg("failed to get ledger end")
}
log.Info().Msgf("Connected to ledger API version: %s", version)
log.Info().Msgf("Current ledger end offset: %s", ledgerEnd)
}package main
import (
"context"
"github.com/smartcontractkit/go-daml/pkg/client"
"github.com/smartcontractkit/go-daml/pkg/model"
"github.com/rs/zerolog/log"
)
func main() {
cl, err := client.NewDamlClient("token", "localhost:8080").
Build(context.Background())
if err != nil {
log.Fatal().Err(err).Msg("failed to build client")
}
ctx := context.Background()
commands := &model.Commands{
ApplicationId: "my-app",
CommandId: "cmd-001",
Party: "Alice",
Commands: []interface{}{},
}
_, err = cl.CommandService.SubmitAndWait(ctx, commands)
if err != nil {
log.Error().Err(err).Msg("command submission failed")
return
}
filter := &model.TransactionFilter{}
contracts, err := cl.EventQueryService.GetActiveContracts(ctx, filter)
if err != nil {
log.Error().Err(err).Msg("failed to query contracts")
return
}
log.Info().Msgf("Retrieved %d active contracts", len(contracts))
}package main
import (
"context"
"os"
"github.com/smartcontractkit/go-daml/pkg/client"
"github.com/smartcontractkit/go-daml/pkg/model"
"github.com/rs/zerolog/log"
)
func main() {
grpcAddress := os.Getenv("GRPC_ADDRESS")
if grpcAddress == "" {
grpcAddress = "localhost:8080"
}
bearerToken := os.Getenv("BEARER_TOKEN")
tlsConfig := client.TlsConfig{}
cl, err := client.NewDamlClient(bearerToken, grpcAddress).
WithTLSConfig(tlsConfig).
Build(context.Background())
if err != nil {
log.Fatal().Err(err).Msg("failed to build DAML client")
}
ctx := context.Background()
userReq := &model.CreateUserRequest{
UserId: "alice@example.com",
PrimaryParty: "Alice",
}
user, err := cl.UserMng.CreateUser(ctx, userReq)
if err != nil {
log.Error().Err(err).Msg("failed to create user")
}
partyReq := &model.AllocatePartyRequest{
PartyIdHint: "NewParty",
DisplayName: "New Party Display Name",
}
party, err := cl.PartyMng.AllocateParty(ctx, partyReq)
if err != nil {
log.Error().Err(err).Msg("failed to allocate party")
}
darBytes, _ := os.ReadFile("./contracts.dar")
uploadReq := &model.UploadDarFileRequest{
DarFile: darBytes,
}
_, err = cl.PackageMng.UploadDarFile(ctx, uploadReq)
if err != nil {
log.Error().Err(err).Msg("failed to upload DAR")
}
log.Info().Msgf("Created user: %s", user.UserId)
log.Info().Msgf("Allocated party: %s", party.PartyId)
}package main
import (
"context"
"os"
"github.com/smartcontractkit/go-daml/pkg/client"
"github.com/smartcontractkit/go-daml/pkg/model"
"github.com/rs/zerolog/log"
)
func main() {
ledgerAddress := "localhost:6865"
adminAddress := "localhost:6866"
bearerToken := os.Getenv("BEARER_TOKEN")
cl, err := client.NewDamlClient(bearerToken, ledgerAddress).
WithAdminAddress(adminAddress).
Build(context.Background())
if err != nil {
log.Fatal().Err(err).Msg("failed to build DAML client")
}
defer cl.Close()
ctx := context.Background()
proposals := []*model.GenerateTransactionProposal{
{
Operation: model.OperationAddReplace,
Serial: 1,
Mapping: &model.NamespaceDelegation{
Namespace: "namespace-fingerprint",
TargetKey: publicKey,
IsRootDelegation: true,
},
Store: &model.StoreID{Value: "authorized"},
},
}
genResp, err := cl.TopologyManagerWrite.GenerateTransactions(ctx, &model.GenerateTransactionsRequest{
Proposals: proposals,
})
if err != nil {
log.Error().Err(err).Msg("failed to generate topology transactions")
return
}
listResp, err := cl.TopologyManagerRead.ListNamespaceDelegation(ctx, &model.ListNamespaceDelegationRequest{})
if err != nil {
log.Error().Err(err).Msg("failed to list namespace delegations")
return
}
log.Info().Msgf("Generated %d topology transactions", len(genResp.GeneratedTransactions))
log.Info().Msgf("Found %d namespace delegations", len(listResp.Results))
}The Go DAML SDK supports separate connections for Ledger API and Admin API endpoints, which is essential for Canton deployments where these services run on different ports.
Use dual connections when:
- Your Canton participant exposes Ledger API and Admin API on different ports (e.g., 6865 and 6866)
- You need to use topology management services alongside ledger operations
- You're working with external party allocation and onboarding transactions
The client automatically routes services to the appropriate connection:
Main Connection (Ledger Address):
- Command Service, Command Completion, Command Submission
- Event Query Service
- State Service, Update Service
- Package Service, Version Service
- Interactive Submission Service
- User Management, Party Management
- Package Management, Participant Pruning
- Command Inspection, Identity Provider Configuration
Admin Connection (Admin Address):
- Topology Manager Write (GenerateTransactions, Authorize, SignTransactions, AddTransactions)
- Topology Manager Read (ListNamespaceDelegation, ListPartyToKeyMapping, ListPartyToParticipant)
cl, err := client.NewDamlClient(token, "localhost:6865").
WithAdminAddress("localhost:6866"). // Optional: if not provided, all services use main address
Build(ctx)
cl.TopologyManagerWrite.GenerateTransactions(ctx, request)Backward Compatibility: If WithAdminAddress() is not called, all services (including topology) use the main ledger
address, maintaining backward compatibility with existing code.
- DAR Extraction: Unzip and parse DAR archive using
UnzipDar() - Manifest Processing: Extract metadata (Main-Dalf, Sdk-Version, package names) from
META-INF/MANIFEST.MF - DAML-LF Version Detection: Determine DAML-LF version from package metadata
- AST Generator Selection: Choose appropriate AST generator (v2 or v3) via factory pattern
- DAML-LF Parsing: Parse protobuf-encoded DAML definitions from .dalf file
- AST Generation: Convert DAML-LF structures to internal AST representation
- Type Classification: Identify Records, Variants, Enums from DAML type definitions
- Package ID Extraction: Extract and embed package IDs in generated code
- Template Application: Apply Go templates to generate type-safe code with custom JSON marshaling
- File Output: Write formatted Go source files to output directory with proper package declarations
The SDK's JSON codec (pkg/codec/json_codec.go) provides comprehensive support for DAML type serialization:
| DAML Type | Go Representation | JSON Format | Notes |
|---|---|---|---|
Party |
PARTY (string) |
String | Party identifiers |
Text |
TEXT (string) |
String | Text values |
Int64 |
INT64 (int64) |
Number | 64-bit integers |
Numeric |
NUMERIC (string) |
String | Arbitrary precision decimals |
Bool |
BOOL (bool) |
Boolean | Boolean values |
Date |
DATE (time.Time) |
String (YYYY-MM-DD) | Date values |
Timestamp |
TIMESTAMP (time.Time) |
String (RFC3339) | Timestamp values |
ContractId |
CONTRACT_ID (string) |
String | Contract identifiers |
Optional T |
OPTIONAL (*interface{}) |
Null or value | Optional values with custom unmarshaling |
[T] |
LIST ([]interface{}) |
Array | Lists with element validation |
GenMap K V |
GEN_MAP ([]MapEntry) |
Array of {key, value} | Generic maps |
| Records | Go struct |
Object | Standard Go structs with field mapping |
| Variants | Go struct with optional fields |
Object with constructor tag | Union types with JSON marshaling |
| Enums | string |
String | Enumeration values |
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes following the existing code style
- Run tests:
make test - Run linting:
make lint - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
- Follow Go best practices and conventions
- Write comprehensive tests for new functionality
- Update documentation for API changes
- Use meaningful commit messages
- Ensure all tests pass before submitting PR
This Go SDK is part of the broader DAML ecosystem:
- DAML - Digital Asset Modeling Language for smart contracts
- DAML Ledger API - gRPC API for interacting with DAML ledgers
- Official DAML SDKs - Java, TypeScript, and other language bindings
- Canton - High-performance DAML ledger implementation
For questions, issues, or contributions:
- Open an issue on GitHub
- Check existing documentation and examples
- Review the test files for usage patterns